/dev/ttyS3 Blog https://ttys3.dev/blog 回首向来萧瑟处 也无荒野也无灯 en-us [email protected] (ttyS3) [email protected] (ttyS3) Sat, 23 Mar 2024 04:10:56 GMT https://ttys3.dev/blog/fedora-linux-cpu-requency-scaling Fedora Linux CPU Frequency Scaling using cpupower https://ttys3.dev/blog/fedora-linux-cpu-requency-scaling <h2 id="命令行方式1----不依赖外部工具"><a href="#命令行方式1----不依赖外部工具" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>命令行方式1 -- 不依赖外部工具</h2><p>查看当前生效的 scaling_driver</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">cat</span> /sys/devices/system/cpu/cpufreq/policy*/scaling_driver </span></code></pre></div><p>查看当前生效的 scaling_governor</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">cat</span> /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor </span></code></pre></div><p>查看可用的 scaling_governor</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">cat</span> /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor </span></code></pre></div><p>设置为高性能模式</p><blockquote><p>对于台式机来说,我觉得没有什么理由不设置为 performance 模式</p></blockquote><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token builtin class-name">echo</span> performance <span class="token operator">|</span> <span class="token function">sudo</span> <span class="token function">tee</span> /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor </span></code></pre></div><p>设置为节能模式</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token builtin class-name">echo</span> powersave <span class="token operator">|</span> <span class="token function">sudo</span> <span class="token function">tee</span> /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor </span></code></pre></div><p>查看其它信息:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ /bin/ls <span class="token variable parameter">-1</span> /sys/devices/system/cpu/cpu0/cpufreq/ </span><span class="code-line">affected_cpus </span><span class="code-line">base_frequency </span><span class="code-line">cpuinfo_max_freq </span><span class="code-line">cpuinfo_min_freq </span><span class="code-line">cpuinfo_transition_latency </span><span class="code-line">energy_performance_available_preferences </span><span class="code-line">energy_performance_preference </span><span class="code-line">related_cpus </span><span class="code-line">scaling_available_governors </span><span class="code-line">scaling_cur_freq </span><span class="code-line">scaling_driver </span><span class="code-line">scaling_governor </span><span class="code-line">scaling_max_freq </span><span class="code-line">scaling_min_freq </span><span class="code-line">scaling_setspeed </span></code></pre></div><p>比如查看当前频率我们读取 <code>scaling_cur_freq</code> 这个文件即可:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">watch</span> <span class="token function">cat</span> /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq </span></code></pre></div><h3 id="scaling-governors-的具体含义"><a href="#scaling-governors-的具体含义" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Scaling governors 的具体含义</h3><p>Scaling governors are power schemes determining the desired frequency for the CPU. Some request a constant frequency, while others implement algorithms to dynamically adjust according to the system load. The governors included in the kernel are:</p><blockquote><p><strong>Note</strong>: Each governor is compatible with any scaling driver, except for <code>intel_pstate</code> and <code>amd_pstate</code> in active mode. These provide pseudo-governors in the form of <code>powersave</code> and <code>performance</code>. See <a href="https://wiki.archlinux.org/title/CPU_frequency_scaling#Autonomous_frequency_scaling">Autonomous frequency scaling</a>.</p></blockquote><table><thead><tr><th>Governor</th><th>Description</th></tr></thead><tbody><tr><td>performance</td><td>Run the CPU at the maximum frequency, obtained from <code>/sys/devices/system/cpu/cpuX/cpufreq/scaling_max_freq</code>.</td></tr><tr><td>powersave</td><td>Run the CPU at the minimum frequency, obtained from <code>/sys/devices/system/cpu/cpuX/cpufreq/scaling_min_freq</code>.</td></tr><tr><td>userspace</td><td>Run the CPU at user-specified frequencies, configurable via <code>/sys/devices/system/cpu/cpuX/cpufreq/scaling_setspeed</code>.</td></tr><tr><td>ondemand</td><td>Scales the frequency dynamically according to current load. Jumps to the highest frequency and then possibly backs off as the idle time increases.</td></tr><tr><td>conservative</td><td>Scales the frequency dynamically according to current load. It does so more gradually than ondemand.</td></tr><tr><td>schedutil</td><td>Scheduler-driven CPU frequency selection <a href="https://lwn.net/Articles/682391/">source</a>, <a href="https://lore.kernel.org/lkml/[email protected]/">source</a>.</td></tr></tbody></table><h2 id="命令行方式2----cpupower"><a href="#命令行方式2----cpupower" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>命令行方式2 -- cpupower</h2><p><code>cpupower</code> 命令在 Fedora 里面由 <code>kernel-tools</code> 包提供,如果没有你需要安装一下:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> kernel-tools </span></code></pre></div><p>查看当前状态:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> cpupower frequency-info </span></code></pre></div><p>直接设置 CPU 工作在特定频率:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">cpupower frequency-set <span class="token variable parameter">-f</span> clock_freq </span></code></pre></div><p>设置 为 performance 模式</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">cpupower frequency-set <span class="token variable parameter">-g</span> performance </span></code></pre></div><p>目前 Fedora 不再提供 <code>cpupower.service</code> 了, 这里从 Arch 抄一个:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Unit</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Description</span><span class="token punctuation">=</span><span class="token attr-value value">Apply cpupower configuration</span> </span><span class="code-line"><span class="token attr-name key">ConditionVirtualization</span><span class="token punctuation">=</span><span class="token attr-value value">!container</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Service</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Type</span><span class="token punctuation">=</span><span class="token attr-value value">oneshot</span> </span><span class="code-line"><span class="token attr-name key">EnvironmentFile</span><span class="token punctuation">=</span><span class="token attr-value value">/etc/default/cpupower</span> </span><span class="code-line"><span class="token attr-name key">ExecStart</span><span class="token punctuation">=</span><span class="token attr-value value">/usr/bin/cpupower $CPUPOWER_ARGS</span> </span><span class="code-line"><span class="token attr-name key">RemainAfterExit</span><span class="token punctuation">=</span><span class="token attr-value value">yes</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Install</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">WantedBy</span><span class="token punctuation">=</span><span class="token attr-value value">multi-user.target</span> </span></code></pre></div><p><code>/etc/default/cpupower</code> 内容如下:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">CPUPOWER_ARGS</span><span class="token operator">=</span><span class="token string">&quot;frequency-set -g performance&quot;</span> </span></code></pre></div><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> systemctl <span class="token builtin class-name">enable</span> <span class="token variable parameter">--now</span> cpupower </span><span class="code-line"><span class="token function">sudo</span> systemctl status cpupower </span><span class="code-line"><span class="token function">sudo</span> cpupower frequency-info </span></code></pre></div><h2 id="命令行方式3----powerprofilesctl"><a href="#命令行方式3----powerprofilesctl" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>命令行方式3 -- powerprofilesctl</h2><p><code>powerprofilesctl</code> 命令由 <code>power-profiles-daemon</code> 包提供。</p><p><a href="https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/blob/main/README.md">https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/blob/main/README.md</a></p><p><a href="https://fedoraproject.org/wiki/Changes/Power_Profiles_Daemon">https://fedoraproject.org/wiki/Changes/Power_Profiles_Daemon</a></p><p>它主要是通过 DBus 与 power-profiles-daemon.service 起来的 <code>power-profiles-daemon</code> 进程通信.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ powerprofilesctl </span><span class="code-line">* performance: </span><span class="code-line"> CpuDriver: intel_pstate </span><span class="code-line"> Degraded: no </span><span class="code-line"> </span><span class="code-line"> balanced: </span><span class="code-line"> CpuDriver: intel_pstate </span><span class="code-line"> PlatformDriver: placeholder </span><span class="code-line"> </span><span class="code-line"> power-saver: </span><span class="code-line"> CpuDriver: intel_pstate </span><span class="code-line"> PlatformDriver: placeholder </span></code></pre></div><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ powerprofilesctl get </span><span class="code-line">performance </span></code></pre></div><h2 id="misc"><a href="#misc" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>misc</h2><h3 id="kernel-tools-里的其它命令"><a href="#kernel-tools-里的其它命令" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>kernel-tools 里的其它命令</h3><p><code>kernel-tools</code> 这个包里除了<code>cpupower</code> 命令, 还有一些其它实用工具:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">rpm</span> <span class="token variable parameter">-qlv</span> kernel-tools <span class="token operator">|</span> rg /usr/bin </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">14696</span> Mar <span class="token number">6</span> 08:00 /usr/bin/centrino-decode </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">78592</span> Mar <span class="token number">6</span> 08:00 /usr/bin/cpupower </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">18792</span> Mar <span class="token number">6</span> 08:00 /usr/bin/gpio-event-mon </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">14696</span> Mar <span class="token number">6</span> 08:00 /usr/bin/gpio-hammer </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">14696</span> Mar <span class="token number">6</span> 08:00 /usr/bin/gpio-watch </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">31096</span> Mar <span class="token number">6</span> 08:00 /usr/bin/iio_event_monitor </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">35192</span> Mar <span class="token number">6</span> 08:00 /usr/bin/iio_generic_buffer </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">123792</span> Mar <span class="token number">6</span> 08:00 /usr/bin/intel-speed-select </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">64461</span> Mar <span class="token number">6</span> 08:00 /usr/bin/kvm_stat </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">14880</span> Mar <span class="token number">6</span> 08:00 /usr/bin/lsgpio </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">22904</span> Mar <span class="token number">6</span> 08:00 /usr/bin/lsiio </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">26984</span> Mar <span class="token number">6</span> 08:00 /usr/bin/page_owner_sort </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">14704</span> Mar <span class="token number">6</span> 08:00 /usr/bin/powernow-k8-decode </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">44224</span> Mar <span class="token number">6</span> 08:00 /usr/bin/slabinfo </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">43736</span> Mar <span class="token number">6</span> 08:00 /usr/bin/tmon </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">132920</span> Mar <span class="token number">6</span> 08:00 /usr/bin/turbostat </span><span class="code-line">-rwxr-xr-x <span class="token number">1</span> root root <span class="token number">39896</span> Mar <span class="token number">6</span> 08:00 /usr/bin/x86_energy_perf_policy </span></code></pre></div><p>Fedora 这个包里并没有包含 <code>cpupower.service</code></p><p>不过它带了一个 <code>/usr/lib/systemd/system/kvm_stat.service</code></p><p>Service that logs KVM kernel module trace events</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">/usr/bin/kvm_stat <span class="token variable parameter">-dtcz</span> <span class="token variable parameter">-s</span> <span class="token number">10</span> <span class="token variable parameter">-L</span> /var/log/kvm_stat.csv </span></code></pre></div><p>看上去是把 kvm 内核模块的状态信息输出到 csv 文件。 并且还带了相应的 logrotate 配置文件 <code>/etc/logrotate.d/kvm_stat</code></p><h3 id="intel_pstate"><a href="#intel_pstate" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>intel_pstate</h3><p>The newer kernel version is using the <code>intel_pstate</code> as the default driver. which is only supported governor <code>performance</code> and <code>powersave</code>.</p><p>In order to use the governor <code>ondemand</code>, you need to disable the <code>intel_pstate</code> driver and using the <code>acpi-cpufreq</code> driver as default.</p><p>Edit the grub configuration.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> nvim /etc/default/grub </span></code></pre></div><p>Add the following configuration.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token variable assign-left">GRUB_CMDLINE_LINUX_DEFAULT</span><span class="token operator">=</span><span class="token string">&quot;intel_pstate=disable&quot;</span> </span></code></pre></div><p>Regenerate your grub.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> grub2-mkconfig <span class="token variable parameter">-o</span> /boot/grub2/grub.cfg </span></code></pre></div><p>Now the <code>intel_pstate</code> driver will be disabled, and the <code>acpi_cpufreq</code> will be enabled by default.</p><p>内核文档: <a href="https://docs.kernel.org/admin-guide/pm/intel_pstate.html">https://docs.kernel.org/admin-guide/pm/intel_pstate.html</a></p><blockquote><p><code>intel_pstate</code> is not modular, so it cannot be unloaded, which means that the only way to pass <strong>early-configuration-time parameters</strong> to it is via the kernel command line. However, its configuration can be adjusted via sysfs to a great extent. In some configurations it even is possible to unregister it via sysfs which allows another CPUFreq scaling driver to be loaded and registered (see below).</p></blockquote><p>不过,我应该大概率用不到 <code>ondemand</code> 模式。</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://www.reddit.com/r/Fedora/comments/jlucb4/how_to_make_a_cpu_governor_change_permanent/">How to make a CPU governor change permanent?</a></p><p><a href="https://discussion.fedoraproject.org/t/how-to-increasing-performance-by-changing-cpu-governor-and-reducing-swappiness/71429">How-to Increasing performance by changing CPU governor and reducing swappiness</a></p><p><a href="https://wiki.archlinux.org/title/CPU_frequency_scaling">ArchLinux WIKI: CPU frequency scaling</a></p><p><a href="https://www.reddit.com/r/Fedora/comments/pr6w7j/note_fedora_cpu_frequency_scaling_using_cpupower/">Note: Fedora CPU Frequency Scaling using cpupower</a></p><p><a href="https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/pm/intel_pstate.rst">https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/pm/intel_pstate.rst</a></p><p><a href="https://www.kernel.org/doc/Documentation/cpu-freq/intel-pstate.txt">https://www.kernel.org/doc/Documentation/cpu-freq/intel-pstate.txt</a></p><p><a href="https://www.kernel.org/doc/html/v6.8/admin-guide/pm/intel_pstate.html">https://www.kernel.org/doc/html/v6.8/admin-guide/pm/intel_pstate.html</a></p><p><a href="https://events.static.linuxfound.org/sites/events/files/slides/LinuxConEurope_2015.pdf">https://events.static.linuxfound.org/sites/events/files/slides/LinuxConEurope_2015.pdf</a></p> Sat, 23 Mar 2024 04:10:56 GMT ttyS3 FedoraFrequencycpupowerLinuxCPU-governor https://ttys3.dev/blog/git-commit-timezone-privacy Github is Leaking Your Commit Timezone https://ttys3.dev/blog/git-commit-timezone-privacy <p>之前有一用一个 Chrome 插件优化 Github UI 体验的,叫 <a href="https://github.com/refined-github/refined-github">refined-github</a></p><p>当然现在我已经没有使用了,主要是由于 Github UI 更新太快,有时候它追不太上。容易导致一些奇怪的 UI问题。</p><p>它有一个神奇的功能是, 你访问他人的 github profile, 或者, 鼠标悬浮在某人头像上时,它会显示出这个用户是在哪个时区,此时此刻他是几点。</p><p>后面我发现,它其实是通过 github restful api 去获取仓库的 commit log 信息, 然后找到最近的一条是作者本人提交的 commit, 通过 git 本身记录的原 commit log 里的时区,就能知道作者的真正所在时区了。</p><h2 id="时区信息是如何获取到的"><a href="#时区信息是如何获取到的" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>时区信息是如何获取到的?</h2><p>但是你如果直接通过 github ui 去访问一个commit , github 总是给你转换成了你当地的时区显示的,因此看不出来。 比如 <a href="https://github.com/refined-github/refined-github/commit/d3e49584cd0f943d7ad1102290ae682f53ee4e97">https://github.com/refined-github/refined-github/commit/d3e49584cd0f943d7ad1102290ae682f53ee4e97</a></p><p>比如通过这个 api: <a href="https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28">https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28</a> 是不行的。</p><p>通过这个 api 你拿到的还是github转换后的 UTC 时区的时间。</p><p>怎么样拿到本地时区呢?</p><p>我们看下这个插件是怎么做的。</p><p>它先访问用户的 events, 比如:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">curl</span> <span class="token string">&#x27;https://api.github.com/users/DerTimonius/events&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;authority: api.github.com&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;accept: application/vnd.github.v3+json&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;accept-language: en-US&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;cache-control: no-cache&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;dnt: 1&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;origin: https://github.com&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;pragma: no-cache&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;referer: https://github.com/refined-github/refined-github/commits/main&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0&#x27;</span> </span></code></pre></div><p>然后就能拿到最近的一些公开的提交事件, 里面会有 commit url:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;repository_id&quot;</span><span class="token operator">:</span> <span class="token number">719513204</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;push_id&quot;</span><span class="token operator">:</span> <span class="token number">15847598750</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;size&quot;</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;distinct_size&quot;</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;ref&quot;</span><span class="token operator">:</span> <span class="token string">&quot;refs/heads/main&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;head&quot;</span><span class="token operator">:</span> <span class="token string">&quot;a27d4e5d855d446e942ce40d03082c2e9ba9964e&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;before&quot;</span><span class="token operator">:</span> <span class="token string">&quot;69eebb7556084c6e2f33d67b3bea599c80ffac08&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;commits&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;sha&quot;</span><span class="token operator">:</span> <span class="token string">&quot;a27d4e5d855d446e942ce40d03082c2e9ba9964e&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;author&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;email&quot;</span><span class="token operator">:</span> <span class="token string">&quot;[email protected]&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Timon Jurschitsch&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;message&quot;</span><span class="token operator">:</span> <span class="token string">&quot;up to chapter 10&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;distinct&quot;</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;url&quot;</span><span class="token operator">:</span> <span class="token string">&quot;https://api.github.com/repos/DerTimonius/next-14-learn/commits/a27d4e5d855d446e942ce40d03082c2e9ba9964e&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>比如这里我们拿到了 <code>https://api.github.com/repos/DerTimonius/next-14-learn/commits/a27d4e5d855d446e942ce40d03082c2e9ba9964e</code></p><p>然后再请求 commit 详情接口:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">curl</span> <span class="token string">&#x27;https://api.github.com/repos/DerTimonius/next-14-learn/commits/a27d4e5d855d446e942ce40d03082c2e9ba9964e&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;authority: api.github.com&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;accept: application/vnd.github.v3+json&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;accept-language: en-US&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;cache-control: no-cache&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;dnt: 1&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;origin: https://github.com&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;pragma: no-cache&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;referer: https://github.com/refined-github/refined-github/commits/main&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0&#x27;</span> </span></code></pre></div><p>然后这里其实还是格式化成了 UTC 时区。嗯, Github 还是比较讲究的。</p><p>但是接下来, 这个插件又请求了:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">curl</span> <span class="token string">&#x27;https://api.github.com/repos/DerTimonius/next-14-learn/commits/a27d4e5d855d446e942ce40d03082c2e9ba9964e&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;authority: api.github.com&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;accept: application/vnd.github.v3.patch&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;accept-language: en-US&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;cache-control: no-cache&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;dnt: 1&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;origin: https://github.com&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;pragma: no-cache&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;referer: https://github.com/refined-github/refined-github/commits/main&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token parameter variable">-H</span> <span class="token string">&#x27;user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0&#x27;</span> </span></code></pre></div><p>没错,请求的 url 一样,但是 <code>accept</code> 头变成了 <code>application/vnd.github.v3.patch</code></p><p>嗯,这应该是拿到原始时区的唯一方式了。</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">From a27d4e5d855d446e942ce40d03082c2e9ba9964e Mon Sep 17 00:00:00 2001 </span><span class="code-line">From: Timon Jurschitsch &lt;[email protected]&gt; </span><span class="code-line">Date: Thu, 16 Nov 2023 12:29:39 +0100 </span><span class="code-line">Subject: [PATCH] up to chapter 10 </span><span class="code-line"> </span><span class="code-line deleted"><span class="token coord">---</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">app/dashboard/(overview)/loading.tsx | 5 +++++ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">app/dashboard/(overview)/page.tsx | 33 ++++++++++++++++++++++++++++ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">app/dashboard/page.tsx | 3 --- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">app/lib/data.ts | 25 +++++++++++++++++---- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">app/ui/dashboard/cards.tsx | 15 +++++++++---- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">app/ui/dashboard/latest-invoices.tsx | 18 +++++++-------- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">app/ui/dashboard/revenue-chart.tsx | 24 ++++++++++---------- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">app/ui/invoices/table.tsx | 10 +++++---- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">package.json | 7 ++++-- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">pnpm-lock.yaml | 2 +- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">10 files changed, 102 insertions(+), 40 deletions(-) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">create mode 100644 app/dashboard/(overview)/loading.tsx </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">create mode 100644 app/dashboard/(overview)/page.tsx </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">delete mode 100644 app/dashboard/page.tsx </span></span></span></code></pre></div><p>然后我们看 <code>Date: Thu, 16 Nov 2023 12:29:39 +0100</code> 这里,原始的时区就出来了。</p><p>插件相关代码: <a href="https://github.com/refined-github/refined-github/blob/d3e49584cd0f943d7ad1102290ae682f53ee4e97/source/features/user-local-time.tsx#L20">https://github.com/refined-github/refined-github/blob/d3e49584cd0f943d7ad1102290ae682f53ee4e97/source/features/user-local-time.tsx#L20</a></p><h2 id="如何避免时区泄露"><a href="#如何避免时区泄露" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何避免时区泄露?</h2><p>已经存在的仓库,当然没得救了。后面的提交至少可以挽回一下吧。</p><p>方法就是使用 git alias, 原来你用 <code>git commit</code> 提交, 现在只需要换成 <code>git ci</code> 即可(为什么喜欢叫 ci? 从 svn 时代就习惯了吧)</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">alias</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token comment">#ci = commit</span> </span><span class="code-line"> <span class="token attr-name key">ci</span> <span class="token punctuation">=</span> <span class="token attr-value value">&quot;<span class="token inner-value">!f() { git commit --date=\&quot;$(date --utc +%Y-%m-%dT%H:%M:%S%z)\&quot; \&quot;${@}\&quot;; }; f</span>&quot;</span> </span><span class="code-line"> <span class="token comment">#cc = cz commit</span> </span><span class="code-line"> <span class="token attr-name key">cc</span> <span class="token punctuation">=</span> <span class="token attr-value value">&quot;<span class="token inner-value">!f() { git cz commit -- --date=\&quot;$(date --utc +%Y-%m-%dT%H:%M:%S%z)\&quot; \&quot;${@}\&quot;; }; f</span>&quot;</span> </span></code></pre></div> Thu, 16 Nov 2023 16:52:40 GMT ttyS3 GitPrivacyTimezone https://ttys3.dev/blog/cross-compile-darwin-target-under-linux Cross Compile Darwin Target Under Linux Troubleshooting https://ttys3.dev/blog/cross-compile-darwin-target-under-linux <p>之前为了方便解密客户端日志,我基于 <a href="https://github.com/Tencent/mars/tree/master/mars/xlog/crypt/decode_log_file_c_impl">https://github.com/Tencent/mars/tree/master/mars/xlog/crypt/decode_log_file_c_impl</a> 写了个简单的命令行工具 <code>xlog-decode</code>。</p><p>这个工具很简单, 就是支持递归地解密当前目录及其下所有的 xlog 文件 (由于是公司项目,因此 xlog 文件的后缀是统一且固定的)。</p><p>如 <code>foo/xxx.xlog</code> 会自动解密在同级目录下,变成 <code>foo/xxx.xlog.log</code></p><p>最近一次编译还是几年前,这不有童鞋需要我给他编译一个 Mac (Intel CPU版) 版的(ps: 我是 Linux 用户),于是有了这个文章。</p><p>原本,这应该也是一个一两分钟的活儿, 不过最终折腾的结果是花了接近2个小时。</p><p>原来的 <code>CMakeLists.txt</code> 如下:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token function">cmake_minimum_required</span> <span class="token punctuation">(</span><span class="token constant">VERSION</span> <span class="token number">3.0</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token function">project</span> <span class="token punctuation">(</span>xlog<span class="token operator">-</span>decode<span class="token punctuation">)</span> </span><span class="code-line"><span class="token function">set</span><span class="token punctuation">(</span><span class="token constant">CMAKE_C_FLAGS</span> <span class="token string">&quot;${CMAKE_C_FLAGS} -O0 -ggdb&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token function">set</span><span class="token punctuation">(</span><span class="token constant">CMAKE_EXE_LINKER_FLAGS</span> <span class="token string">&quot;${CMAKE_EXE_LINKER_FLAGS} -lz&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"># <span class="token control-flow keyword">for</span> log </span><span class="code-line"><span class="token function">add_definitions</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token constant">DLOG_USE_COLOR</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">add_definitions</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token constant">DBUILD_SHARED_LIBS</span><span class="token operator">=</span><span class="token constant">OFF</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"># <span class="token control-flow keyword">for</span> zstd </span><span class="code-line"># <span class="token function">option</span><span class="token punctuation">(</span><span class="token constant">ZSTD_BUILD_STATIC</span> <span class="token string">&quot;BUILD STATIC LIBRARIES&quot;</span> <span class="token constant">ON</span><span class="token punctuation">)</span> </span><span class="code-line"># <span class="token function">option</span><span class="token punctuation">(</span><span class="token constant">ZSTD_BUILD_SHARED</span> <span class="token string">&quot;BUILD SHARED LIBRARIES&quot;</span> <span class="token constant">OFF</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">include</span><span class="token punctuation">(</span><span class="token maybe-class-name">GNUInstallDirs</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">add_executable</span><span class="token punctuation">(</span>xlog<span class="token operator">-</span>decode main<span class="token punctuation">.</span><span class="token property-access">c</span> log<span class="token punctuation">.</span><span class="token property-access">c</span> micro<span class="token operator">-</span>ecc<span class="token operator">-</span>master<span class="token operator">/</span>uECC<span class="token punctuation">.</span><span class="token property-access">c</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token function">target_link_libraries</span><span class="token punctuation">(</span>xlog<span class="token operator">-</span>decode zstd z<span class="token punctuation">)</span> </span></code></pre></div><p><code>Makefile</code> 主要是方便编译的脚本 (没错,当时我主力还是 ArchLinux, 还没怎么用 Fedora. paru! paru!):</p><div class="relative"><pre><code class="code-highlight language-makefile"><span class="code-line"><span class="token symbol target">build</span><span class="token punctuation">:</span> </span><span class="code-line"> cmake -B build . </span><span class="code-line"> cd build &amp;&amp; make </span><span class="code-line"> </span><span class="code-line"><span class="token symbol target">deps/arch</span><span class="token punctuation">:</span> </span><span class="code-line"> paru -S --needed zstd </span><span class="code-line"> </span><span class="code-line"><span class="token symbol target">deps/ubuntu</span><span class="token punctuation">:</span> </span><span class="code-line"> apt install -y make cmake g++ gcc zlib1g-dev zlib1g libzstd-dev libzstd1 </span><span class="code-line"> </span><span class="code-line"><span class="token symbol target">install</span><span class="token punctuation">:</span> build </span><span class="code-line"> install -vD -m 755 build/xlog-decode /usr/local/bin/xlog-decode </span><span class="code-line"> </span><span class="code-line"><span class="token symbol target">clean</span><span class="token punctuation">:</span> </span><span class="code-line"> -rm -rf ./build </span></code></pre></div><p>这两个文件都没啥问题。</p><p>然后我有一个 <code>mac.sh</code> 用于执行 Mac 交叉编译的:</p><div class="remark-code-title">mac.sh</div><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token important shebang">#!/usr/bin/env bash</span> </span><span class="code-line"> </span><span class="code-line"><span class="token builtin class-name">set</span> <span class="token variable parameter">-eou</span> pipefail </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Don&#x27;t forget to adjust this to your standalone toolchain path</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">TOOLCHAIN_PATH</span><span class="token operator">=</span>/usr/local/darwin-ndk-x86_64 </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># There should be no need to edit anything between this line and the next</span> </span><span class="code-line"><span class="token comment"># -----------------------------------------------------------------------</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">CROSS_COMPILE</span><span class="token operator">=</span>x86_64-apple-darwin22.2 </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">CROSS_PATH</span><span class="token operator">=</span><span class="token variable">${TOOLCHAIN_PATH}</span>/bin </span><span class="code-line"><span class="token comment"># Set the compiler and linker</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">CPP</span><span class="token operator">=</span><span class="token variable">${CROSS_PATH}</span>/<span class="token variable">${CROSS_COMPILE}</span>-c++ </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">AR</span><span class="token operator">=</span><span class="token variable">${CROSS_PATH}</span>/<span class="token variable">${CROSS_COMPILE}</span>-ar </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">AS</span><span class="token operator">=</span><span class="token variable">${CROSS_PATH}</span>/<span class="token variable">${CROSS_COMPILE}</span>-as </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">NM</span><span class="token operator">=</span><span class="token variable">${CROSS_PATH}</span>/<span class="token variable">${CROSS_COMPILE}</span>-nm </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">CC</span><span class="token operator">=</span><span class="token variable">${CROSS_PATH}</span>/<span class="token variable">${CROSS_COMPILE}</span>-cc </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">CXX</span><span class="token operator">=</span><span class="token variable">${CROSS_PATH}</span>/<span class="token variable">${CROSS_COMPILE}</span>-c++ </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">LD</span><span class="token operator">=</span><span class="token variable">${CROSS_PATH}</span>/<span class="token variable">${CROSS_COMPILE}</span>-ld </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">RANLIB</span><span class="token operator">=</span><span class="token variable">${CROSS_PATH}</span>/<span class="token variable">${CROSS_COMPILE}</span>-ranlib </span><span class="code-line"> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">CFLAGS</span><span class="token operator">=</span><span class="token string">&quot;-I/home/ttys3/repo/cpp/xlog-decode/zstd/lib&quot;</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">LDFLAGS</span><span class="token operator">=</span><span class="token string">&quot;-L/usr/local/darwin-ndk-x86_64/lib -L/home/ttys3/repo/cpp/xlog-decode/zstd/lib&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">LD_LIBRARY_PATH</span><span class="token operator">=</span>/usr/local/darwin-ndk-x86_64/lib:/home/ttys3/repo/cpp/xlog-decode/zstd/lib </span><span class="code-line"> </span><span class="code-line"><span class="token function">make</span> </span></code></pre></div><p>toolchain 我也是已经安装好的,并且确定是工作的.</p><p>注: 这里有个 zstd 库是单独静态编译好的 (因为要交叉编译,所以不能用动态链接,会很麻烦)</p><p>然后,其实这个脚本本身也是没啥问题的。</p><p>但是为什么编译报错了呢?</p><blockquote><p>/usr/bin/ld: unknown option: -dynamic</p></blockquote><p>为什么, 明明已经指定了 <code>export LD=${CROSS_PATH}/${CROSS_COMPILE}-ld</code>, 但是 cmake 就是不用呢?</p><p>所以, 编译失败的原因显然是, cmake 对于这个 <code>LD</code> env 的识别出现了破坏性的变更。不过都过了2年多了,咱也不常用 cmake 这玩意, 也不知道它做了啥改变。</p><p>因此,足足折腾了近2个小时,才找到了一个朴素的修复方法:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">ln</span> <span class="token variable parameter">-s</span> /usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin22.2-ld /usr/local/darwin-ndk-x86_64/bin/ld </span></code></pre></div><p>没错,就是要把 <code>x86_64-apple-darwin22.2-ld</code> 链接为 <code>ld</code>, 这样, cmake 在生成 makefile 的时候,就自动用上了 apple toolchain 里的 ld 了。</p><p>结论:</p><blockquote><p>if <code>ld</code> not exists, cmake will always try to use <code>/usr/bin/ld</code>, which will fuck you up</p></blockquote><p>这个解决办法和思路来自: <a href="https://github.com/rust-lang/rust/issues/52657#issuecomment-407481607">https://github.com/rust-lang/rust/issues/52657#issuecomment-407481607</a></p><p>另, 由于当初图方便,在 main.c 里面内嵌了解密的密钥,因此这个仓库暂时是没有公开的。</p><p>如果有人有需要,后面有空我再整理开源吧。 很多时候不开源,只是为了避免麻烦,因为涉及到安全和隐私,开源之前都是要再三检查所有 commit log, 这挺费时间的。</p> Sat, 28 Oct 2023 12:04:58 GMT ttyS3 cross-compileclinuxdarwintroubleshooting https://ttys3.dev/blog/how-to-send-notify-under-linux How to Send Desktop Notifications under Linux https://ttys3.dev/blog/how-to-send-notify-under-linux <p>有这个文章是因为,曾经不小心看到了 Arch wiki 里有个神奇的页面, 里面介绍了&quot;回&quot;字的X种写法</p><p>然后我在 C+ glib2 这种写法上面翻车了: <a href="https://wiki.archlinux.org/title/Desktop_notifications#C">https://wiki.archlinux.org/title/Desktop_notifications#C</a></p><p>完全按 wiki 来的:</p><p>Dependency: <code>glib2</code> Build with:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">gcc <span class="token variable parameter">-o</span> hello_world <span class="token variable"><span class="token variable">`</span>pkg-config <span class="token variable parameter">--cflags</span> <span class="token variable parameter">--libs</span> gio-2.0<span class="token variable">`</span></span> hello_world.c </span></code></pre></div><div class="remark-code-title">hello_world.c</div><div class="relative"><pre><code class="code-highlight language-c"><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;gio/gio.h&gt;</span></span> </span><span class="code-line"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> GApplication <span class="token operator">*</span>application <span class="token operator">=</span> <span class="token function">g_application_new</span> <span class="token punctuation">(</span><span class="token string">&quot;hello.world&quot;</span><span class="token punctuation">,</span> G_APPLICATION_FLAGS_NONE<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">g_application_register</span> <span class="token punctuation">(</span>application<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> GNotification <span class="token operator">*</span>notification <span class="token operator">=</span> <span class="token function">g_notification_new</span> <span class="token punctuation">(</span><span class="token string">&quot;Hello world!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">g_notification_set_body</span> <span class="token punctuation">(</span>notification<span class="token punctuation">,</span> <span class="token string">&quot;This is an example notification.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> GIcon <span class="token operator">*</span>icon <span class="token operator">=</span> <span class="token function">g_themed_icon_new</span> <span class="token punctuation">(</span><span class="token string">&quot;dialog-information&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">g_notification_set_icon</span> <span class="token punctuation">(</span>notification<span class="token punctuation">,</span> icon<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">g_application_send_notification</span> <span class="token punctuation">(</span>application<span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">,</span> notification<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">g_object_unref</span> <span class="token punctuation">(</span>icon<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">g_object_unref</span> <span class="token punctuation">(</span>notification<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">g_object_unref</span> <span class="token punctuation">(</span>application<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>结果却非常意外,没有任何通知出现。</p><p>但是使用 <code>notify-send hello</code> 却是工作得很正常(后面发现使用 <code>libnotify</code> 或 <code>dbus</code> 的方式也都工作正常)。</p><p>当时也就放弃了。后面看到了文档:</p><blockquote><p>Warning: gnome-shell uses desktop files to find extra information (app icon, name) about the sender of the notification. If you don&#x27;t have a <strong>desktop file</strong> whose <strong>base name</strong> matches <strong>the application id</strong>, then your notification will <strong>not</strong> show up.</p></blockquote><p>这个 <a href="https://developer-old.gnome.org/GNotification/">GNOME 的旧文档</a>,反而把事情说得比新文档明白通俗易懂一些。</p><p>新版本的文档是这样写的:</p><p><a href="https://developer.gnome.org/documentation/tutorials/notifications.html#prerequisites">https://developer.gnome.org/documentation/tutorials/notifications.html#prerequisites</a></p><p>In order to use notifications in GNOME you will need to:</p><ul><li><p>use GApplication or GtkApplication</p></li><li><p>provide <strong>a valid desktop file</strong> with the <strong>same name</strong> as your <strong>application id</strong></p></li><li><p>ensure that your application can be activated via D-Bus</p></li></ul><p>文档在第二点说明了这个问题。但是没有写得那么容易让人看懂。(如果不提供会发生什么?作为用户,完全不知道,如果这条不满足,通知会直接不显示)</p><p>好了,回到最开始的问题, 由于新建 GNOME 应用的时候用的是 <code>g_application_new (&quot;hello.world&quot;, G_APPLICATION_FLAGS_NONE);</code>, 因此, application id 为 <code>hello.world</code>, 所以,必须要存在一个名为 <code>hello.world.desktop</code> 的 desktop 文件, 里面至少要有 <code>Name</code> 和 <code>Icon</code> 等.</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token punctuation">[</span><span class="token maybe-class-name">Desktop</span> <span class="token maybe-class-name">Entry</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token maybe-class-name">Name</span><span class="token operator">=</span><span class="token maybe-class-name">GNotification</span> <span class="token maybe-class-name">Hello</span> <span class="token maybe-class-name">World</span> </span><span class="code-line"><span class="token maybe-class-name">Exec</span><span class="token operator">=</span><span class="token operator">/</span>usr<span class="token operator">/</span>local<span class="token operator">/</span>bin<span class="token operator">/</span>hello<span class="token punctuation">.</span><span class="token property-access">world</span> <span class="token operator">%</span><span class="token constant">U</span> </span><span class="code-line"><span class="token maybe-class-name">Icon</span><span class="token operator">=</span>hello<span class="token operator">-</span>world </span></code></pre></div><p>然后你还要把 <code>hello-world.png</code> 的图标文件 和 <code>hello.world.desktop</code> desktop 文件放在正确的位置.</p><p>这样这个通知才能发送出来.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://wiki.archlinux.org/title/Desktop_notifications">https://wiki.archlinux.org/title/Desktop_notifications</a></p><p><a href="https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5708">https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5708</a></p><p><a href="https://github.com/flatpak/xdg-desktop-portal-gtk/pull/394/files">https://github.com/flatpak/xdg-desktop-portal-gtk/pull/394/files</a></p> Thu, 19 Oct 2023 17:35:01 GMT ttyS3 notificationsnotifygnomegnome-application-id https://ttys3.dev/blog/openzfs 关于 OpenZFS https://ttys3.dev/blog/openzfs <h2 id="kernel-modules"><a href="#kernel-modules" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>kernel modules</h2><p>以 pve 8 (基于 debian 12) 为例,里面的 zfs 模块在 <code>/lib/modules/$(uname -r)/zfs/</code> 目录。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">root@pve:~<span class="token comment"># ls -lh /lib/modules/$(uname -r)/zfs/</span> </span><span class="code-line">total <span class="token number">4</span>.1M </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root 569K Jun <span class="token number">17</span> <span class="token number">13</span>:58 icp.ko </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root 241K Jun <span class="token number">17</span> <span class="token number">13</span>:58 spl.ko </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root 29K Jun <span class="token number">17</span> <span class="token number">13</span>:58 zavl.ko </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root 215K Jun <span class="token number">17</span> <span class="token number">13</span>:58 zcommon.ko </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root <span class="token number">6</span>.9M Jun <span class="token number">17</span> <span class="token number">13</span>:58 zfs.ko </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root 416K Jun <span class="token number">17</span> <span class="token number">13</span>:58 zlua.ko </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root 211K Jun <span class="token number">17</span> <span class="token number">13</span>:58 znvpair.ko </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root 373K Jun <span class="token number">17</span> <span class="token number">13</span>:58 zunicode.ko </span><span class="code-line">-rw-r--r-- <span class="token number">1</span> root root 1007K Jun <span class="token number">17</span> <span class="token number">13</span>:58 zzstd.ko </span></code></pre></div><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">root@pve:~<span class="token comment"># modinfo spl | grep -E &#x27;author|description|license|filename&#x27;</span> </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/spl.ko </span><span class="code-line">license: GPL </span><span class="code-line">author: OpenZFS </span><span class="code-line">description: Solaris Porting Layer </span></code></pre></div><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">ls</span> <span class="token variable parameter">-1</span> /lib/modules/<span class="token variable"><span class="token variable">$(</span><span class="token function">uname</span> <span class="token variable parameter">-r</span><span class="token variable">)</span></span>/zfs/ <span class="token operator">|</span> <span class="token function">xargs</span> -I<span class="token string">&#x27;{}&#x27;</span> <span class="token function">basename</span> <span class="token string">&#x27;{}&#x27;</span> .ko <span class="token operator">|</span> <span class="token function">xargs</span> -I<span class="token string">&#x27;{}&#x27;</span> <span class="token function">sh</span> <span class="token variable parameter">-c</span> <span class="token string">&#x27;modinfo &quot;{}&quot; | grep -E &quot;author|description|license|filename&quot;; echo &quot;-------------------------&quot;&#x27;</span> </span></code></pre></div><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/icp.ko </span><span class="code-line">license: CDDL </span><span class="code-line">author: OpenZFS </span><span class="code-line">------------------------- </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/spl.ko </span><span class="code-line">license: GPL </span><span class="code-line">author: OpenZFS </span><span class="code-line">description: Solaris Porting Layer </span><span class="code-line">------------------------- </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/zavl.ko </span><span class="code-line">license: CDDL </span><span class="code-line">author: OpenZFS </span><span class="code-line">description: Generic AVL tree implementation </span><span class="code-line">------------------------- </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/zcommon.ko </span><span class="code-line">license: CDDL </span><span class="code-line">author: OpenZFS </span><span class="code-line">description: Generic ZFS support </span><span class="code-line">------------------------- </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/zfs.ko </span><span class="code-line">license: CDDL </span><span class="code-line">author: OpenZFS </span><span class="code-line">description: ZFS </span><span class="code-line">------------------------- </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/zlua.ko </span><span class="code-line">license: Dual MIT/GPL </span><span class="code-line">author: Lua.org </span><span class="code-line">description: Lua Interpreter <span class="token keyword">for</span> ZFS </span><span class="code-line">------------------------- </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/znvpair.ko </span><span class="code-line">license: CDDL </span><span class="code-line">author: OpenZFS </span><span class="code-line">description: Generic name/value pair implementation </span><span class="code-line">------------------------- </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/zunicode.ko </span><span class="code-line">license: CDDL </span><span class="code-line">author: OpenZFS </span><span class="code-line">description: Unicode implementation </span><span class="code-line">------------------------- </span><span class="code-line">filename: /lib/modules/6.2.16-3-pve/zfs/zzstd.ko </span><span class="code-line">license: Dual BSD/GPL </span><span class="code-line">description: ZSTD Compression <span class="token keyword">for</span> ZFS </span><span class="code-line">------------------------- </span></code></pre></div><p>OpenZFS 的 license 均为 CDDL</p><p>另外这个 <code>zfs/spl.ko</code> 模块引起了我的注意, 描述为 <strong>Solaris Porting Layer</strong> , 似乎是个中间层的 porting 代码。</p><p>查看 <a href="https://openzfs.org/wiki/Reduce_code_differences">https://openzfs.org/wiki/Reduce_code_differences</a> 果然如此:</p><blockquote><p>Reduce code differences Jump to navigationJump to search One of the technical goals of OpenZFS is to reduce code differences between the various platforms that support ZFS. To accomplish this, we will:</p><p>Create a &quot;porting layer&quot; to abstract out the platform-specific code. The &quot;Solaris Porting Layer&quot; (SPL) is a good start at this. We can improve it by moving illumos/Solaris-specific code out of the main files and into platform-specific files. Split the ZPL into platform-independent and platform-specific parts. Long-term, consider if we can create a common repository to use for platform-independent ZFS code, rather than treating illumos as the de facto upstream repository. Any code in this repo would need to be able to be tested in a platform-independent way (e.g. in userland using libzpool), so that changes tested on one platform can be expected to work on every platform. Code tested by ztest would be the first candidate for this. Userland ZFS ioctls would enable running /sbin/zfs and /sbin/zpool, and thus most of the TestRunner test suite against libzpool. See Platform code differences for specific information on areas of divergence.</p></blockquote><p>由于 ZFS 是从 illumos/Solaris port 到 linux 的,而 ZFS 又不想因为 Linux 而改动其核心代码,因此就有了这个 &quot;porting layer&quot; 把 Linux 上没有的一些东西做兼容处理。</p> Thu, 05 Oct 2023 04:08:08 GMT ttyS3 openzfszfs https://ttys3.dev/blog/flameshot-troubelshooting Flameshot troubleshooting https://ttys3.dev/blog/flameshot-troubelshooting <h2 id="使用-gnome-自定义快捷键无法调起-flameshot-gui"><a href="#使用-gnome-自定义快捷键无法调起-flameshot-gui" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>使用 GNOME 自定义快捷键无法调起 flameshot gui</h2><p>这个解决办法主要来自 <a href="https://github.com/flatpak/xdg-desktop-portal/issues/1070#issuecomment-1762884545">https://github.com/flatpak/xdg-desktop-portal/issues/1070#issuecomment-1762884545</a></p><p>注意, 这里比较奇怪的是,直接在 GNOME 自定义 key binding 里面的 command 写上 <code>/usr/bin/env QT_QPA_PLATFORM=wayland flameshot gui</code> 是不会工作的.</p><p>必须通过 shell 脚本执行。暂时不知道原因。</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">sudo</span> <span class="token function">tee</span> /usr/local/bin/flameshot-gui-workaround <span class="token operator">&gt;</span> /dev/null <span class="token operator">&lt;&lt;</span><span class="token string">&#x27;EOF&#x27; </span></span><span class="code-line"><span class="token string">#!/bin/bash </span></span><span class="code-line"><span class="token string"># workaround thanks to https://github.com/flatpak/xdg-desktop-portal/issues/1070#issuecomment-1762884545 </span></span><span class="code-line"><span class="token string">env QT_QPA_PLATFORM=wayland flameshot gui </span></span><span class="code-line"><span class="token string"> </span></span><span class="code-line"><span class="token string">EOF</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">chmod</span> a+x /usr/local/bin/flameshot-gui-workaround </span></code></pre></div><p>然后我们把原来配置的 GNOME 自定义 shortcut 的 command 从 <code>flameshot gui</code> 换成 <code>/usr/local/bin/flameshot-gui-workaround</code> :</p><div><img alt="flameshot-shortcut-2023-10-20_01-15.png" src="https://ttys3.dev/static/assets/flameshot-shortcut-2023-10-20_01-15-I4GQ6HA7.png" width="1283" height="960"/></div><h2 id="点击-take-screenshot--无法显示截图界面"><a href="#点击-take-screenshot--无法显示截图界面" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>点击 &quot;Take Screenshot&quot; 无法显示截图界面</h2><p>如果观察系统日志,会发现类似:</p><blockquote><p>xdg-desktop-por[848788]: Failed to show access dialog: GDBus.Error:org.freedesktop.DBus.Error.AccessDenied: Only the focused app is allowed to show a system access dialog</p></blockquote><p>解决办法是:</p><p><a href="https://github.com/flameshot-org/flameshot/issues/2868#issuecomment-1312470098">https://github.com/flameshot-org/flameshot/issues/2868#issuecomment-1312470098</a></p><p>Hi guys, I was going to add my 2 cents on how it doesn&#x27;t work for me, but then I experimented a bit more and it started working.</p><p>OS: Fedora 37, Wayland, Gnome 43, Flameshot: 12.1.0 installed using dnf, xdg-desktop-portal-1.15.0-1.fc37</p><p>What I did to make it work:</p><p>Run flameshot Open flameshot&#x27;s settings window(I also maximized the window to lower the chances of loosing focus of that window - probably not needed) Take a screenshot using flameshot - I clicked the tray icon that came from a gnome extension Permissions question should appear - grant it It should now work fine without asking for permissions next time you take a screenshot The same can be done for flameshot run from the terminal, or triggered by a keyboard shortcut. You need to run flameshot in the terminal instead of using gnome launcher, and repeat the above steps. In this case I don&#x27;t know if it&#x27;s the flameshot settings window that needs to be actively focused to trigger the permissions prompt. But it&#x27;s one of those.</p><p>In summary, I can now run flameshot from the tray icon, from terminal, from the ALT+F2(gnome&#x27;s run command tool) and it takes screenshots without asking for permissions.</p><h2 id="点击-take-screenshot-直接被拒绝"><a href="#点击-take-screenshot-直接被拒绝" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>点击 &quot;Take Screenshot&quot; 直接被拒绝</h2><p>与前面说的 &quot;GDBus.Error:org.freedesktop.DBus.Error.AccessDenied: Only the focused app is allowed to show a system access dialog&quot; 错误不同, 这次是直接被拒绝。 出现这种情况,基本上是因为,在第一次弹出权限确认窗口的时候,你没有选择(直接按esc也相当于回答了no), 或者选择了 no, 后面就会直接拒绝了。</p><p>日志信息:</p><blockquote><p>org.flameshot.Flameshot.desktop[887167]: flameshot: error: Unable to capture screen</p></blockquote><p>这种情况下,我们已经没办法再让这个允许权限的窗口弹出来显示了。</p><p>好在万能的 github 用户也给出了解决办法: <a href="https://github.com/flameshot-org/flameshot/issues/2868#issuecomment-1384310540">https://github.com/flameshot-org/flameshot/issues/2868#issuecomment-1384310540</a></p><p>先 dump 一下当前的配置:</p><div class="relative"><pre><code class="code-highlight language-python"><span class="code-line"><span class="token keyword">import</span> dbus </span><span class="code-line"><span class="token keyword">import</span> json </span><span class="code-line"> </span><span class="code-line">bus <span class="token operator">=</span> dbus<span class="token punctuation">.</span>SessionBus<span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line">perm <span class="token operator">=</span> bus<span class="token punctuation">.</span>get_object<span class="token punctuation">(</span><span class="token string">&#x27;org.freedesktop.impl.portal.PermissionStore&#x27;</span><span class="token punctuation">,</span> <span class="token string">&#x27;/org/freedesktop/impl/portal/PermissionStore&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line">perm_iface <span class="token operator">=</span> dbus<span class="token punctuation">.</span>Interface<span class="token punctuation">(</span>perm<span class="token punctuation">,</span> dbus_interface<span class="token operator">=</span><span class="token string">&#x27;org.freedesktop.impl.portal.PermissionStore&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line">perm_iface<span class="token punctuation">.</span>Lookup<span class="token punctuation">(</span><span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token keyword">print</span><span class="token punctuation">(</span>json<span class="token punctuation">.</span>dumps<span class="token punctuation">(</span>perm_iface<span class="token punctuation">.</span>Lookup<span class="token punctuation">(</span><span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> indent<span class="token operator">=</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span></code></pre></div><p>正常情况下,dump 成 json 后的结果应该类似:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&quot;yes&quot;</span> </span><span class="code-line"> <span class="token punctuation">]</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;kitty&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&quot;yes&quot;</span> </span><span class="code-line"> <span class="token punctuation">]</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;org.flameshot.Flameshot&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&quot;yes&quot;</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token number">0</span> </span><span class="code-line"><span class="token punctuation">]</span> </span></code></pre></div><p>这里主要是检查是否存在 <code>org.flameshot.Flameshot</code> 并且值应该为 <code>[&quot;yes&quot;]</code>.</p><p>比如这种情况就是之前拒绝过的情况(值为 <code>no</code>):</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token operator">&gt;&gt;</span><span class="token operator">&gt;</span> perm_iface.Lookup<span class="token punctuation">(</span><span class="token string">&quot;screenshot&quot;</span>, <span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">(</span>dbus.Dictionary<span class="token punctuation">(</span><span class="token punctuation">{</span>dbus.String<span class="token punctuation">(</span><span class="token string">&#x27;&#x27;</span><span class="token punctuation">)</span>: dbus.Array<span class="token punctuation">(</span><span class="token punctuation">[</span>dbus.String<span class="token punctuation">(</span><span class="token string">&#x27;yes&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">]</span>, <span class="token assign-left variable">signature</span><span class="token operator">=</span>dbus.Signature<span class="token punctuation">(</span><span class="token string">&#x27;s&#x27;</span><span class="token punctuation">))</span>, dbus.String<span class="token punctuation">(</span><span class="token string">&#x27;org.flameshot.Flameshot&#x27;</span><span class="token punctuation">)</span>: dbus.Array<span class="token punctuation">(</span><span class="token punctuation">[</span>dbus.String<span class="token punctuation">(</span><span class="token string">&#x27;no&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">]</span>, <span class="token assign-left variable">signature</span><span class="token operator">=</span>dbus.Signature<span class="token punctuation">(</span><span class="token string">&#x27;s&#x27;</span><span class="token punctuation">))</span><span class="token punctuation">}</span>, <span class="token assign-left variable">signature</span><span class="token operator">=</span>dbus.Signature<span class="token punctuation">(</span><span class="token string">&#x27;sas&#x27;</span><span class="token punctuation">))</span>, dbus.Byte<span class="token punctuation">(</span><span class="token number">0</span>, <span class="token assign-left variable">variant_level</span><span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">))</span> </span></code></pre></div><p>我们把它 set 回去成 <code>yes</code>:</p><div class="relative"><pre><code class="code-highlight language-python"><span class="code-line">perm_iface<span class="token punctuation">.</span>Set<span class="token punctuation">(</span><span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">,</span> dbus<span class="token punctuation">.</span>Boolean<span class="token punctuation">(</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string">&quot;&quot;</span><span class="token punctuation">:</span><span class="token punctuation">[</span><span class="token string">&quot;yes&quot;</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">&quot;org.flameshot.Flameshot&quot;</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">&quot;yes&quot;</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">,</span> dbus<span class="token punctuation">.</span>Byte<span class="token punctuation">(</span><span class="token number">0x0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token operator">&gt;&gt;</span><span class="token operator">&gt;</span> perm_iface<span class="token punctuation">.</span>Lookup<span class="token punctuation">(</span><span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;screenshot&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">(</span>dbus<span class="token punctuation">.</span>Dictionary<span class="token punctuation">(</span><span class="token punctuation">{</span>dbus<span class="token punctuation">.</span>String<span class="token punctuation">(</span><span class="token string">&#x27;&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">:</span> dbus<span class="token punctuation">.</span>Array<span class="token punctuation">(</span><span class="token punctuation">[</span>dbus<span class="token punctuation">.</span>String<span class="token punctuation">(</span><span class="token string">&#x27;yes&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> signature<span class="token operator">=</span>dbus<span class="token punctuation">.</span>Signature<span class="token punctuation">(</span><span class="token string">&#x27;s&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dbus<span class="token punctuation">.</span>String<span class="token punctuation">(</span><span class="token string">&#x27;org.flameshot.Flameshot&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">:</span> dbus<span class="token punctuation">.</span>Array<span class="token punctuation">(</span><span class="token punctuation">[</span>dbus<span class="token punctuation">.</span>String<span class="token punctuation">(</span><span class="token string">&#x27;yes&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> signature<span class="token operator">=</span>dbus<span class="token punctuation">.</span>Signature<span class="token punctuation">(</span><span class="token string">&#x27;s&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span> signature<span class="token operator">=</span>dbus<span class="token punctuation">.</span>Signature<span class="token punctuation">(</span><span class="token string">&#x27;sas&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dbus<span class="token punctuation">.</span>Byte<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> variant_level<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span></code></pre></div><h2 id="保存到文件-无反应"><a href="#保存到文件-无反应" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>&quot;保存到文件&quot; 无反应</h2><p>不知道什么时候开始 flameshot 保存到文件的功能不工作了。也没报错。</p><p>今天抽空看了下。</p><p>找到了这个 issue <a href="https://github.com/flameshot-org/flameshot/issues/207">https://github.com/flameshot-org/flameshot/issues/207</a></p><p>给了我灵感。</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">❯ <span class="token function">cat</span> ~/.config/flameshot/flameshot.ini </span><span class="code-line"><span class="token punctuation">[</span>General<span class="token punctuation">]</span> </span><span class="code-line"><span class="token assign-left variable">checkForUpdates</span><span class="token operator">=</span>false </span><span class="code-line"><span class="token assign-left variable">contrastOpacity</span><span class="token operator">=</span><span class="token number">188</span> </span><span class="code-line"><span class="token assign-left variable">showStartupLaunchMessage</span><span class="token operator">=</span>false </span></code></pre></div><p>发现配置就这几行。 但是明明 GUI 配置界面显示了保存路径是 <code>/home/ttys3/Pictures/Screenshots</code> 啊?</p><p>重新进入 general 配置,发现有一个 Prefered save file extension 没有值, 于是随手选了一个 avif 格式, 然后再看文件配置,发现已经有保存路径的配置了:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">saveAsFileExtension<span class="token operator">=</span>avif </span><span class="code-line">savePath<span class="token operator">=</span><span class="token operator">/</span>home<span class="token operator">/</span>ttys3<span class="token operator">/</span><span class="token maybe-class-name">Pictures</span><span class="token operator">/</span><span class="token maybe-class-name">Screenshots</span> </span><span class="code-line">savePathFixed<span class="token operator">=</span><span class="token boolean">true</span> </span></code></pre></div><p>然后再测试保存到文件的功能,也 OK 了. 看来就是 saveAsFileExtension 为空导致文本配置并没有保存成功。问题是它没取到 savePath 居然不报错。</p><div><img alt="2023-09-28_02-19-flameshot-config-save-path-and-save-extension.avif.png" src="https://ttys3.dev/static/assets/2023-09-28_02-19-flameshot-config-save-path-and-save-extension.avif-ILI375BI.png" width="997" height="1288"/></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p>Taking screenshots with Java under Wayland <a href="https://adangel.org/2022/02/06/java-screenshot/">https://adangel.org/2022/02/06/java-screenshot/</a></p><p><a href="https://flameshot.org/docs/guide/wayland-help/#i-am-asked-to-share-my-screen-every-time">https://flameshot.org/docs/guide/wayland-help/#i-am-asked-to-share-my-screen-every-time</a></p><p><a href="https://github.com/flameshot-org/flameshot/issues/2868#issuecomment-1384310540">https://github.com/flameshot-org/flameshot/issues/2868#issuecomment-1384310540</a></p><p><a href="https://github.com/flameshot-org/flameshot/issues/3326">https://github.com/flameshot-org/flameshot/issues/3326</a></p><p><a href="https://github.com/flatpak/xdg-desktop-portal/issues/1070#issuecomment-1771302632">https://github.com/flatpak/xdg-desktop-portal/issues/1070#issuecomment-1771302632</a></p><p>flameshot 官方文档里的 troubleshooting 也是不错的参考</p><p><a href="https://flameshot.org/docs/guide/troubleshooting/">https://flameshot.org/docs/guide/troubleshooting/</a></p><p><a href="https://flameshot.org/docs/guide/troubleshooting/#flameshot-icon-is-visible-in-tray-area-but-when-i-click-on-it-nothing-happens">https://flameshot.org/docs/guide/troubleshooting/#flameshot-icon-is-visible-in-tray-area-but-when-i-click-on-it-nothing-happens</a></p><p>First try the using the command flameshot gui in terminal. This does exactly what clicking on the tray icon does. (make sure can you see Flameshot icon in the tray area)</p><p>If the above step didn&#x27;t work:</p><p>Open 3 terminals</p><p>Kill Flameshot if it is already open using <code>pkill flameshot</code></p><p>In the first terminal run <code>dbus-monitor --session sender=org.flameshot.Flameshot</code></p><p>In the second terminal run <code>flameshot</code></p><p>In the third terminal run <code>flameshot gui</code></p> Wed, 27 Sep 2023 18:13:18 GMT ttyS3 flameshotscrenshot https://ttys3.dev/blog/fix-next.js-text-content-does-not-match-server-rendered-html-error fix Cloudflare cache + Next.js “Text content does not match server-rendered HTML” https://ttys3.dev/blog/fix-next.js-text-content-does-not-match-server-rendered-html-error <h2 id="background"><a href="#background" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>background</h2><p>recently I migrated my Blog from Hugo to <a href="https://github.com/timlrx/tailwind-nextjs-starter-blog">timlrx/tailwind-nextjs-starter-blog</a></p><p>I deploy the blog via Netlify and serve it via Cloudflare proxy.</p><h2 id="how-to-see-the-problem"><a href="#how-to-see-the-problem" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>how to see the problem</h2><p>open browser console, you&#x27;ll see errros like this:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line">4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span> <span class="token maybe-class-name">Uncaught</span> <span class="token class-name known-class-name">Error</span><span class="token operator">:</span> <span class="token maybe-class-name">Minified</span> <span class="token maybe-class-name">React</span> error #<span class="token number">425</span><span class="token punctuation">;</span> visit https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>reactjs<span class="token punctuation">.</span><span class="token property-access">org</span><span class="token operator">/</span>docs<span class="token operator">/</span>error<span class="token operator">-</span>decoder<span class="token punctuation">.</span><span class="token property-access">html</span><span class="token operator">?</span>invariant<span class="token operator">=</span><span class="token number">425</span> <span class="token control-flow keyword">for</span> the full message or use the non<span class="token operator">-</span>minified dev environment <span class="token control-flow keyword">for</span> full errors and additional helpful warnings<span class="token punctuation">.</span> </span><span class="code-line"> <span class="token property-access">at</span> <span class="token function">si</span> <span class="token punctuation">(</span>4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">140010</span><span class="token punctuation">)</span> </span><span class="code-line"> at <span class="token function">tJ</span> <span class="token punctuation">(</span>4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">23531</span><span class="token punctuation">)</span> </span><span class="code-line"> at 4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">94483</span> </span><span class="code-line"> at <span class="token function">oR</span> <span class="token punctuation">(</span>4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">98923</span><span class="token punctuation">)</span> </span><span class="code-line"> at <span class="token function">oM</span> <span class="token punctuation">(</span>4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">90251</span><span class="token punctuation">)</span> </span><span class="code-line"> at 4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">86358</span> </span><span class="code-line"> at 4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">86365</span> </span><span class="code-line"> at <span class="token function">oy</span> <span class="token punctuation">(</span>4f0b14e9<span class="token operator">-</span>f6a6045a21104f01<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">86470</span><span class="token punctuation">)</span> </span><span class="code-line"> at <span class="token constant">E</span> <span class="token punctuation">(</span><span class="token number">629</span><span class="token operator">-</span>498c73b757a747b0<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">94713</span><span class="token punctuation">)</span> </span><span class="code-line"> at <span class="token maybe-class-name">MessagePort</span><span class="token punctuation">.</span><span class="token constant">C</span> <span class="token punctuation">(</span><span class="token number">629</span><span class="token operator">-</span>498c73b757a747b0<span class="token punctuation">.</span><span class="token property-access">js</span><span class="token operator">:</span><span class="token number">1</span><span class="token operator">:</span><span class="token number">95266</span><span class="token punctuation">)</span> </span></code></pre></div><p>what is &quot;<strong>Uncaught Error: Minified React error #425</strong>&quot; ?</p><p>according <a href="https://reactjs.org/docs/error-decoder.html?invariant=425">https://reactjs.org/docs/error-decoder.html?invariant=425</a></p><blockquote><p>Error Decoder In the minified production build of React, we avoid sending down full error messages in order to reduce the number of bytes sent over the wire.</p></blockquote><blockquote><p>We highly recommend using the development build locally when debugging your app since it tracks additional debug info and provides helpful warnings about potential problems in your apps, but if you encounter an exception while using the production build, this page will reassemble the original text of the error.</p></blockquote><blockquote><p>The full text of the error you just encountered is:</p></blockquote><blockquote><blockquote><p>Text content does not match server-rendered HTML.</p></blockquote></blockquote><p>note: Netlify blog also post <a href="https://www.netlify.com/blog/fix-next-js-react-hydration-error/">an article about the &quot;Text content does not match server-rendered HTML&quot; issue</a>, but our&#x27;s problem is not the same like that one.</p><h2 id="how-i-got-the-solution"><a href="#how-i-got-the-solution" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>how I got the solution?</h2><p>local run <code>next build &amp;&amp; next serve</code> everything is fine.</p><p>go to Cloudflare site config: <strong>Caching</strong> -- <strong>Configuration</strong></p><p>enable &quot;<strong>Development Mode</strong>&quot;, everything is fine.</p><p>so it is a Cloudflare caching problem with Next.js</p><h2 id="the-solution"><a href="#the-solution" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>the solution</h2><p>go to Cloudflare site config: <strong>Speed</strong> -- <strong>Optimization</strong></p><p>switch to &quot;<strong>Content Optimization</strong>&quot; tab, then scroll down to &quot;<strong>Auto Minify</strong>&quot; and uncheck &quot;<strong>HTML</strong>&quot; checkbox.</p><div><img alt="disable cloudflare Content Optimization Auto Minify HTML" src="https://ttys3.dev/static/assets/e4ff9e1b-b4af-47a8-9efe-6b7c8d4f693b-VJUNO2LU.png" width="2474" height="1390"/></div><p>for fast the cache expire progress, we can go to Cloudflare site config:</p><p><strong>Caching</strong> -- <strong>Configuration</strong> -- <strong>Purge Cache</strong> and click &quot;<strong>Purge Everything</strong>&quot; button and confirm.</p> Sun, 23 Jul 2023 05:53:23 GMT ttyS3 troubleshootnext-jscloudflare https://ttys3.dev/blog/how-to-export-all-your-evernote-notes-to-markdown How to Export All Your Evernote Notes to Markdown https://ttys3.dev/blog/how-to-export-all-your-evernote-notes-to-markdown <p><a href="https://github.com/vzhd1701/evernote-backup">evernote-backup</a></p><blockquote><p>Quickly sync all your notes into the SQLite database for backup. Export all backed up notes in *.enex format, as notebooks or single notes.</p></blockquote><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">pip <span class="token function">install</span> <span class="token parameter variable">--user</span> evernote-backup </span></code></pre></div><h2 id="step-1-database-initialization"><a href="#step-1-database-initialization" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Step 1. Database initialization</h2><p>By default, it will prompt you to enter your account credentials. You can provide them beforehand with <code>--user</code> and <code>--password</code> options.</p><p>If you log in to Evernote with Google or Apple accounts, you must use the <code>--oauth</code> option.</p><p>To connect to Yinxiang instead of Evernote, use <code>--backend china</code> option. Unfortunately, OAuth is not supported for Yinxiang yet.</p><p>log in to Evernote with Google:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">evernote-backup init-db <span class="token parameter variable">--oauth</span> </span></code></pre></div><h2 id="step-2-downloading-evernote-data"><a href="#step-2-downloading-evernote-data" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Step 2. Downloading Evernote data</h2><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">evernote-backup <span class="token function">sync</span> </span></code></pre></div><h2 id="step-3-exporting-enex-files"><a href="#step-3-exporting-enex-files" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Step 3. Exporting *.enex files</h2><p>By default, evernote-backup will export notes by packing them into <strong>notebooks</strong>, one *.enex file each. If you want to extract notes as separate files, use the <code>--single-notes</code> flag.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">evernote-backup <span class="token builtin class-name">export</span> --single-notes evernote-enex-backup/ </span></code></pre></div><h2 id="step-4-convert-it-into-markdown"><a href="#step-4-convert-it-into-markdown" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Step 4. Convert it into markdown</h2><p><a href="https://github.com/akosbalasko/yarle">https://github.com/akosbalasko/yarle</a></p><p><code>useHashTags</code> should set to <code>false</code> to avoid tags get hash prefix like <code>#tagname</code></p><p>markdown template:</p><div class="relative"><pre><code class="code-highlight language-markdown"><span class="code-line"><span class="token front-matter-block"><span class="token punctuation">---</span> </span></span><span class="code-line"><span class="token front-matter-block"><span class="token front-matter language-yaml yaml"><span class="token punctuation">{</span>title<span class="token punctuation">-</span>block<span class="token punctuation">}</span>title<span class="token punctuation">:</span> <span class="token punctuation">{</span>title<span class="token punctuation">}</span><span class="token punctuation">{</span>end<span class="token punctuation">-</span>title<span class="token punctuation">-</span>block<span class="token punctuation">}</span> </span></span></span><span class="code-line"><span class="token front-matter-block"><span class="token front-matter language-yaml yaml"><span class="token punctuation">{</span>created<span class="token punctuation">-</span>at<span class="token punctuation">-</span>block<span class="token punctuation">}</span>date<span class="token punctuation">:</span> <span class="token punctuation">{</span>created<span class="token punctuation">-</span>at<span class="token punctuation">}</span><span class="token punctuation">{</span>end<span class="token punctuation">-</span>created<span class="token punctuation">-</span>at<span class="token punctuation">-</span>block<span class="token punctuation">}</span> </span></span></span><span class="code-line"><span class="token front-matter-block"><span class="token front-matter language-yaml yaml"><span class="token punctuation">{</span>updated<span class="token punctuation">-</span>at<span class="token punctuation">-</span>block<span class="token punctuation">}</span>lastmod<span class="token punctuation">:</span> <span class="token punctuation">{</span>updated<span class="token punctuation">-</span>at<span class="token punctuation">}</span><span class="token punctuation">{</span>end<span class="token punctuation">-</span>updated<span class="token punctuation">-</span>at<span class="token punctuation">-</span>block<span class="token punctuation">}</span> </span></span></span><span class="code-line"><span class="token front-matter-block"><span class="token front-matter language-yaml yaml"><span class="token punctuation">{</span>source<span class="token punctuation">-</span>url<span class="token punctuation">-</span>block<span class="token punctuation">}</span>sourceurl<span class="token punctuation">:</span> <span class="token punctuation">{</span>source<span class="token punctuation">-</span>url<span class="token punctuation">}</span><span class="token punctuation">{</span>end<span class="token punctuation">-</span>source<span class="token punctuation">-</span>url<span class="token punctuation">-</span>block<span class="token punctuation">}</span> </span></span></span><span class="code-line"><span class="token front-matter-block"><span class="token front-matter language-yaml yaml"><span class="token punctuation">{</span>tags<span class="token punctuation">-</span>array<span class="token punctuation">-</span>block<span class="token punctuation">}</span> </span></span></span><span class="code-line"><span class="token front-matter-block"><span class="token front-matter language-yaml yaml"><span class="token atrule key">tags</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>tags<span class="token punctuation">-</span>array<span class="token punctuation">}</span> </span></span></span><span class="code-line"><span class="token front-matter-block"><span class="token front-matter language-yaml yaml"><span class="token punctuation">{</span>end<span class="token punctuation">-</span>tags<span class="token punctuation">-</span>array<span class="token punctuation">-</span>block<span class="token punctuation">}</span></span> </span></span><span class="code-line"><span class="token front-matter-block"><span class="token punctuation">---</span></span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TOCInline</span> <span class="token attr-name">toc</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span>{props.toc}</span> <span class="token attr-name">asDisclosure</span> <span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> </span><span class="code-line">{content-block}{content}{end-content-block} </span><span class="code-line"> </span></code></pre></div><h2 id="step-5-choose-an-alternative"><a href="#step-5-choose-an-alternative" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Step 5. Choose an alternative</h2><p>noteapps.info 笔记应用程序百科全书</p><p>无广告。没有营销。 只有流行笔记应用的截图、功能列表和价格。</p><p><a href="https://noteapps.info/">https://noteapps.info/</a></p><p><a href="https://github.com/toeverything/AFFiNE">https://github.com/toeverything/AFFiNE</a></p><p><a href="https://obsidian.md/">https://obsidian.md/</a></p> Thu, 13 Jul 2023 11:03:46 GMT ttyS3 evernotemarkdownexportnote-taking https://ttys3.dev/blog/migrate-from-hugo-to-tailwind-nextjs-blog Blog 从 Hugo 迁移到 Tailwind Next.js Blog https://ttys3.dev/blog/migrate-from-hugo-to-tailwind-nextjs-blog <p><a href="https://github.com/timlrx/tailwind-nextjs-starter-blog">https://github.com/timlrx/tailwind-nextjs-starter-blog</a></p><p><a href="https://github.com/timlrx/pliny">https://github.com/timlrx/pliny</a></p><h2 id="migration-repo"><a href="#migration-repo" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>migration repo</h2><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">git</span> checkout <span class="token variable parameter">-b</span> hugo </span><span class="code-line"><span class="token function">git</span> push origin hugo </span><span class="code-line"> </span><span class="code-line"><span class="token function">git</span> branch <span class="token variable parameter">-D</span> main </span><span class="code-line"><span class="token function">git</span> checkout <span class="token variable parameter">--orphan</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token function">rm</span> <span class="token variable parameter">-rf</span> ./* </span><span class="code-line"><span class="token function">rm</span> <span class="token variable parameter">-rf</span> .forestry .gitignore .gitmodules </span><span class="code-line"> </span><span class="code-line"> <span class="token function">cp</span> <span class="token variable parameter">-rav</span> ~/repo/blog/nextjs-ttys3.dev/* <span class="token class-name builtin">.</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token function">cp</span> <span class="token variable parameter">-rav</span> ~/repo/blog/nextjs-ttys3.dev/.* <span class="token class-name builtin">.</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"> meld <span class="token class-name builtin">.</span> ~/repo/blog/nextjs-ttys3.dev </span><span class="code-line"> bcompare <span class="token class-name builtin">.</span> ~/repo/blog/nextjs-ttys3.dev </span><span class="code-line"> </span><span class="code-line"> <span class="token function">git</span> remote <span class="token function">add</span> origin [email protected]:ttys3/ttys3.dev.git </span><span class="code-line"> </span><span class="code-line"> <span class="token function">git</span> push origin main <span class="token variable parameter">-f</span> </span></code></pre></div><h2 id="guide-to-mdx"><a href="#guide-to-mdx" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Guide to MDX</h2><p><a href="https://kabartolo.github.io/chicago-docs-demo/docs/mdx-guide/">https://kabartolo.github.io/chicago-docs-demo/docs/mdx-guide/</a></p><h2 id="netlify-related"><a href="#netlify-related" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>netlify related</h2><h3 id="build-failed"><a href="#build-failed" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>build Failed</h3><blockquote><p>plugin &quot;@netlify/plugin-nextjs&quot; failed</p></blockquote><blockquote><p>Error: The directory &quot;/opt/build/repo/public&quot; does not contain a Next.js production build. Perhaps the build command was not run, or you specified the wrong publish directory. However, a &#x27;.next&#x27; directory was found with a production build. Consider changing your &#x27;publish&#x27; directory to &#x27;.next&#x27; If you are using &quot;next export&quot; then you should set the environment variable NETLIFY_NEXT_PLUGIN_SKIP to &quot;true&quot;.</p></blockquote><p><strong>Build configuration</strong></p><p>Runtime <code>Next.js</code></p><p>Build command <code>npm run build</code></p><p>fixup:</p><p>change Publish directory <code>public</code> =&gt; Publish directory <code>.next</code></p><h3 id="nextjs-integrations"><a href="#nextjs-integrations" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Next.js integrations</h3><p><a href="https://docs.netlify.com/integrations/frameworks/#next-js">https://docs.netlify.com/integrations/frameworks/#next-js</a></p><h3 id="nodejs-environment"><a href="#nodejs-environment" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Node.js environment</h3><p><a href="https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-environment">https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-environment</a></p><h3 id="nextjs-on-netlify"><a href="#nextjs-on-netlify" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Next.js on Netlify</h3><p><a href="https://docs.netlify.com/integrations/frameworks/next-js/overview/">https://docs.netlify.com/integrations/frameworks/next-js/overview/</a></p><h3 id="troubleshooting-nextjs-on-netlify"><a href="#troubleshooting-nextjs-on-netlify" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Troubleshooting Next.js on Netlify</h3><p><a href="https://docs.netlify.com/integrations/frameworks/next-js/troubleshooting/">https://docs.netlify.com/integrations/frameworks/next-js/troubleshooting/</a></p><h2 id="troubleshoot"><a href="#troubleshoot" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>troubleshoot</h2><h3 id="1-md-to-mdx-rename"><a href="#1-md-to-mdx-rename" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. <code>.md</code> to <code>.mdx</code> rename</h3><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">rnr <span class="token variable parameter">-r</span> <span class="token variable parameter">-f</span> <span class="token string">&#x27;.md&#x27;</span> <span class="token string">&#x27;.mdx&#x27;</span> <span class="token class-name builtin">.</span> </span><span class="code-line">rnr <span class="token variable parameter">-r</span> <span class="token variable parameter">-f</span> <span class="token string">&#x27;.mdxx&#x27;</span> <span class="token string">&#x27;.mdx&#x27;</span> <span class="token class-name builtin">.</span> </span></code></pre></div><h3 id="2-markdown-link-compitable-with-mdx"><a href="#2-markdown-link-compitable-with-mdx" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. markdown link compitable with MDX</h3><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">❯ rg <span class="token string">&#x27;&lt;http(s)?://.+?&gt;&#x27;</span> <span class="token variable parameter">-l</span> <span class="token operator">|</span> <span class="token function">wc</span> <span class="token variable parameter">-l</span> </span><span class="code-line"><span class="token number">70</span> </span></code></pre></div><p>neither Rust or Golang Regex engine support look around (look ahead or look after)</p><p>we need use a tool support PCRE like <a href="https://github.com/adamreisnz/replace-in-file">https://github.com/adamreisnz/replace-in-file</a></p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">npm</span> i <span class="token variable parameter">-g</span> replace-in-file </span></code></pre></div><p>debug the Regex : <a href="https://regex101.com/r/9UPYQr/1">https://regex101.com/r/9UPYQr/1</a></p><p><code>config.js</code> content:</p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line"><span class="token comment">//config.js</span> </span><span class="code-line">module<span class="token punctuation">.</span><span class="token property-access">exports</span> <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token string">&#x27;./**/*.mdx&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token keyword module">from</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token language-regex regex-source"><span class="token punctuation group">(?&lt;!</span><span class="token escape special-escape">\]</span><span class="token punctuation group">)</span>&lt;http<span class="token punctuation group">(</span>s<span class="token punctuation group">)</span><span class="token number quantifier">?</span>:<span class="token escape">\/</span><span class="token escape">\/</span><span class="token punctuation group">(</span><span class="token char-class"><span class="token punctuation char-class-punctuation">[</span><span class="token operator char-class-negation">^</span><span class="token punctuation char-class-punctuation">[</span><span class="token escape special-escape">\]</span><span class="token punctuation char-class-punctuation">]</span></span><span class="token number quantifier">+?</span><span class="token punctuation group">)</span>&gt;<span class="token punctuation group">(?!</span><span class="token escape special-escape">\]</span><span class="token punctuation group">)</span></span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token literal-property property">to</span><span class="token operator">:</span> <span class="token string">&#x27; http\$1://\$2 &#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">;</span> </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">replace-in-file <span class="token variable parameter">--configFile</span><span class="token operator">=</span>config.js </span></code></pre></div><p>remove not used frontmatter fields:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token comment"># check</span> </span><span class="code-line">rg <span class="token string">&#x27;^slug:\s+[a-zA-Z_-]+&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># delete</span> </span><span class="code-line"><span class="token function">sed</span> <span class="token variable parameter">-E</span> <span class="token variable parameter">-i</span> <span class="token string">&#x27;/^slug:\s+[a-zA-Z_-]+/d&#x27;</span> <span class="token variable"><span class="token variable">`</span>rg <span class="token variable parameter">-l</span> slug<span class="token variable">`</span></span> </span></code></pre></div><h3 id="3-null-safe-join-of-tags"><a href="#3-null-safe-join-of-tags" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. null-safe join of tags</h3><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">commit baab006f840d07fe5a1ea27a6c586a118d21870c </span><span class="code-line">Author: ttyS3 &lt;[email protected]&gt; </span><span class="code-line">Date: 2023-07-10 20:31:17 +0800 </span><span class="code-line"> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> chore: null-safe join of tags </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line">diff --git a/layouts/ListLayout.tsx b/layouts/ListLayout.tsx </span><span class="code-line">index fb967f7..7c94a9d 100644 </span><span class="code-line deleted"><span class="token coord">--- a/layouts/ListLayout.tsx</span> </span><span class="code-line inserted"><span class="token coord">+++ b/layouts/ListLayout.tsx</span> </span><span class="code-line">@@ -66,7 +66,7 @@ export default function ListLayout({ </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">}: ListLayoutProps) { </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> const [searchValue, setSearchValue] = useState(&#x27;&#x27;) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> const filteredBlogPosts = posts.filter((post) =&gt; { </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> const searchContent = post.title + post.summary + post.tags.join(&#x27; &#x27;) </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> const searchContent = post.title + post.summary + (post.tags ?? []).join(&#x27; &#x27;) </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> return searchContent.toLowerCase().includes(searchValue.toLowerCase()) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> }) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line">@@ -129,7 +129,7 @@ export default function ListLayout({ </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> &lt;/Link&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;/h3&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;div className=&quot;flex flex-wrap&quot;&gt; </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> {tags.map((tag) =&gt; ( </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> {(tags ?? []).map((tag) =&gt; ( </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> &lt;Tag key={tag} text={tag} /&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> ))} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;/div&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>diff --git a/layouts/PostLayout.tsx b/layouts/PostLayout.tsx </span><span class="code-line">index 0562fd9..c5b165c 100644 </span><span class="code-line deleted"><span class="token coord">--- a/layouts/PostLayout.tsx</span> </span><span class="code-line inserted"><span class="token coord">+++ b/layouts/PostLayout.tsx</span> </span><span class="code-line">@@ -123,7 +123,7 @@ export default function PostLayout({ content, authorDetails, next, prev, childre </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> Tags </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;/h2&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;div className=&quot;flex flex-wrap&quot;&gt; </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> {tags.map((tag) =&gt; ( </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> {(tags ?? []).map((tag) =&gt; ( </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> &lt;Tag key={tag} text={tag} /&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> ))} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;/div&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>diff --git a/pages/index.tsx b/pages/index.tsx </span><span class="code-line">index f8fafeb..c084f88 100644 </span><span class="code-line deleted"><span class="token coord">--- a/pages/index.tsx</span> </span><span class="code-line inserted"><span class="token coord">+++ b/pages/index.tsx</span> </span><span class="code-line">@@ -57,7 +57,7 @@ export default function Home({ posts }: InferGetStaticPropsType&lt;typeof getStatic </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> &lt;/Link&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;/h2&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;div className=&quot;flex flex-wrap&quot;&gt; </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> {tags.map((tag) =&gt; ( </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> {(tags ?? []).map((tag) =&gt; ( </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> &lt;Tag key={tag} text={tag} /&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> ))} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;/div&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>diff --git a/pages/tags/[tag].tsx b/pages/tags/[tag].tsx </span><span class="code-line">index f939fc6..4437f40 100644 </span><span class="code-line deleted"><span class="token coord">--- a/pages/tags/[tag].tsx</span> </span><span class="code-line inserted"><span class="token coord">+++ b/pages/tags/[tag].tsx</span> </span><span class="code-line">@@ -23,7 +23,7 @@ export const getStaticProps = async (context) =&gt; { </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> const tag = context.params.tag as string </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> const filteredPosts = allCoreContent( </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> allBlogs.filter( </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> (post) =&gt; post.draft !== true &amp;&amp; post.tags.map((t) =&gt; kebabCase(t)).includes(tag) </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> (post) =&gt; post.draft !== true &amp;&amp; (post.tags ?? []).map((t) =&gt; kebabCase(t)).includes(tag) </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> ) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> ) </span></span></span></code></pre></div><h3 id="3-build-problem"><a href="#3-build-problem" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. build problem</h3><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"> ❯ <span class="token function">npm</span> run build </span><span class="code-line"> </span><span class="code-line">Failed to compile. </span><span class="code-line"> </span><span class="code-line">./pages/404.tsx </span><span class="code-line"><span class="token number">9</span>:36 Error: Replace <span class="token variable"><span class="token variable">`</span>t-6·pb-8<span class="token variable">`</span></span> with <span class="token variable"><span class="token variable">`</span>b-8·pt-6<span class="token variable">`</span></span> prettier/prettier </span></code></pre></div><p>solution:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">❯ <span class="token function">npm</span> run lint </span><span class="code-line"> </span><span class="code-line"><span class="token operator">&gt;</span> [email protected] lint </span><span class="code-line"><span class="token operator">&gt;</span> next lint <span class="token variable parameter">--fix</span> <span class="token variable parameter">--dir</span> pages <span class="token variable parameter">--dir</span> components <span class="token variable parameter">--dir</span> lib <span class="token variable parameter">--dir</span> layouts <span class="token variable parameter">--dir</span> scripts </span></code></pre></div><p>the fixup like:</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">diff --git a/pages/404.tsx b/pages/404.tsx </span><span class="code-line">index 2bdf448..873137d 100644 </span><span class="code-line deleted"><span class="token coord">--- a/pages/404.tsx</span> </span><span class="code-line inserted"><span class="token coord">+++ b/pages/404.tsx</span> </span><span class="code-line">@@ -6,7 +6,7 @@ export default function FourZeroFour() { </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> &lt;&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;PageSEO title=&quot;Page Not Found&quot; description=&quot;Sorry we couldn&#x27;t find this page :(&quot; /&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;div className=&quot;flex flex-col items-start justify-start md:mt-24 md:flex-row md:items-center md:justify-center md:space-x-6&quot;&gt; </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> &lt;div className=&quot;space-x-2 pt-6 pb-8 md:space-y-5&quot;&gt; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> &lt;div className=&quot;space-x-2 pb-8 pt-6 md:space-y-5&quot;&gt; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> &lt;h1 className=&quot;text-6xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 md:border-r-2 md:px-6 md:text-8xl md:leading-14&quot;&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> 404 </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;/h1&gt; </span></span></span></code></pre></div><p>empty tags still cause problem:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token function">λ</span> <span class="token punctuation">(</span><span class="token maybe-class-name">Server</span><span class="token punctuation">)</span> server<span class="token operator">-</span>side renders at <span class="token function">runtime</span> <span class="token punctuation">(</span>uses getInitialProps or getServerSideProps<span class="token punctuation">)</span> </span><span class="code-line"><span class="token function">○</span> <span class="token punctuation">(</span><span class="token maybe-class-name">Static</span><span class="token punctuation">)</span> automatically rendered <span class="token keyword module">as</span> <span class="token keyword">static</span> <span class="token constant">HTML</span> <span class="token punctuation">(</span>uses no initial props<span class="token punctuation">)</span> </span><span class="code-line"><span class="token function">●</span> <span class="token punctuation">(</span><span class="token constant">SSG</span><span class="token punctuation">)</span> automatically generated <span class="token keyword module">as</span> <span class="token keyword">static</span> <span class="token constant">HTML</span> <span class="token operator">+</span> <span class="token class-name known-class-name">JSON</span> <span class="token punctuation">(</span>uses getStaticProps<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">(</span>node<span class="token operator">:</span><span class="token number">825002</span><span class="token punctuation">)</span> <span class="token maybe-class-name">ExperimentalWarning</span><span class="token operator">:</span> <span class="token maybe-class-name">Importing</span> <span class="token class-name known-class-name">JSON</span> modules is an experimental feature<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">This</span></span> feature could change at any <span class="token function">time</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token maybe-class-name">Use</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">node --trace-warnings ...</span><span class="token string template-punctuation">`</span></span> to show where the warning was created<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">RSS</span> feed generated<span class="token operator spread">...</span> </span><span class="code-line"><span class="token maybe-class-name">Sitemap</span> generated<span class="token operator spread">...</span> </span><span class="code-line"><span class="token literal-property property">file</span><span class="token operator">:</span><span class="token operator">/</span><span class="token comment">//home/user001/repo/blog/ttys3.dev/node_modules/pliny/utils/generate-rss.js:43</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token parameter">post</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> post<span class="token punctuation">.</span><span class="token property-access">tags</span><span class="token punctuation">.</span><span class="token function property-access method">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">t</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token maybe-class-name">GithubSlugger</span><span class="token punctuation">.</span><span class="token function property-access method">slug</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function property-access method">includes</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token operator">^</span> </span><span class="code-line"> </span><span class="code-line"><span class="token class-name known-class-name">TypeError</span><span class="token operator">:</span> <span class="token maybe-class-name">Cannot</span> read properties <span class="token keyword">of</span> <span class="token keyword nil">undefined</span> <span class="token punctuation">(</span>reading <span class="token string">&#x27;map&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"> at file<span class="token operator">:</span><span class="token operator">/</span><span class="token comment">//home/user001/repo/blog/ttys3.dev/node_modules/pliny/utils/generate-rss.js:43:29</span> </span><span class="code-line"> at <span class="token class-name known-class-name">Array</span><span class="token punctuation">.</span><span class="token function property-access method">filter</span> <span class="token punctuation">(</span><span class="token operator">&lt;</span>anonymous<span class="token operator">&gt;</span><span class="token punctuation">)</span> </span><span class="code-line"> at <span class="token function">generateRSS</span> <span class="token punctuation">(</span>file<span class="token operator">:</span><span class="token operator">/</span><span class="token comment">//home/user001/repo/blog/ttys3.dev/node_modules/pliny/utils/generate-rss.js:42:38)</span> </span></code></pre></div><p>workaround:</p><p>edit <code>contentlayer.config.ts</code> set a default value for <code>tags</code>:</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">diff --git a/contentlayer.config.ts b/contentlayer.config.ts </span><span class="code-line">index 3f6c2b8..929806e 100644 </span><span class="code-line deleted"><span class="token coord">--- a/contentlayer.config.ts</span> </span><span class="code-line inserted"><span class="token coord">+++ b/contentlayer.config.ts</span> </span><span class="code-line">@@ -44,7 +44,7 @@ export const Blog = defineDocumentType(() =&gt; ({ </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> fields: { </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> title: { type: &#x27;string&#x27;, required: true }, </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> date: { type: &#x27;date&#x27;, required: true }, </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> tags: { type: &#x27;list&#x27;, of: { type: &#x27;string&#x27; } }, </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> tags: { type: &#x27;list&#x27;, of: { type: &#x27;string&#x27; }, default: [] }, </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> lastmod: { type: &#x27;date&#x27; }, </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> draft: { type: &#x27;boolean&#x27; }, </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> summary: { type: &#x27;string&#x27; }, </span></span></span></code></pre></div><p>ref contentlayer <a href="https://www.contentlayer.dev/docs/reference/source-files/field-types-defe41e9#list">list</a></p><h3 id="page-bundle-image-support"><a href="#page-bundle-image-support" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>page bundle image support</h3><p>currently does not support page bundle images, see</p><p><a href="https://github.com/timlrx/pliny/issues/106">https://github.com/timlrx/pliny/issues/106</a></p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">npm</span> <span class="token function">install</span> git+https://github.com/ttys3/remark-copy-linked-files.git </span></code></pre></div><p>ref to <a href="https://unifiedjs.com/learn/guide/create-a-plugin/#plugin-basics">https://unifiedjs.com/learn/guide/create-a-plugin/#plugin-basics</a></p><p>and <a href="https://mdxjs.com/docs/extending-mdx/#components--plugins">https://mdxjs.com/docs/extending-mdx/#components--plugins</a></p><p>mainly hack:</p><p><code>dataDir</code> is default to <code>data</code></p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line"> <span class="token comment">// path is something like `/path-to-project-root/_mdx_bundler_entry_point-3e814d53-72fb-474b-8853-f64f1521e36a.mdx`</span> </span><span class="code-line"> <span class="token comment">// after contentlayer (which uses mdx-bundler)</span> </span><span class="code-line"> <span class="token comment">// `file.data.rawDocumentData.sourceFilePath` begin with `blog/xxx`, does not include the `data` dir</span> </span><span class="code-line"> <span class="token keyword">const</span> fullpath <span class="token operator">=</span> <span class="token function">resolve</span><span class="token punctuation">(</span> </span><span class="code-line"> cwd<span class="token punctuation">,</span> </span><span class="code-line"> dataDir<span class="token punctuation">,</span> </span><span class="code-line"> file<span class="token operator">?.</span>data<span class="token operator">?.</span>rawDocumentData<span class="token operator">?.</span>sourceFilePath <span class="token operator">?</span> <span class="token function">dirname</span><span class="token punctuation">(</span>file<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">.</span><span class="token property-access">rawDocumentData</span><span class="token punctuation">.</span><span class="token property-access">sourceFilePath</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">&#x27;&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> platformNormalizedUrl<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>and edit <code>contentlayer.config.ts</code>, add to top:</p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line"><span class="token keyword module">import</span> <span class="token imports">remarkCopyLinkedFiles</span> <span class="token keyword module">from</span> <span class="token string">&#x27;remark-copy-linked-files&#x27;</span> </span></code></pre></div><p>under <code>remarkPlugins</code>, add below before <code>remarkGfm</code>:</p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line"><span class="token punctuation">[</span>remarkCopyLinkedFiles<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">destinationDir</span><span class="token operator">:</span> process<span class="token punctuation">.</span><span class="token function property-access method">cwd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span><span class="token string">&quot;/public/static/images/blog/&quot;</span><span class="token punctuation">,</span> <span class="token literal-property property">staticPath</span><span class="token operator">:</span> <span class="token string">&quot;/static/images/blog&quot;</span><span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> </span></code></pre></div><p>other ref:</p><p><a href="https://github.com/timlrx/pliny/blob/1e82c4e45fb2ea8533aeb6c265822acf312e7067/packages/pliny/src/mdx-plugins/remark-img-to-jsx.ts#L13">https://github.com/timlrx/pliny/blob/1e82c4e45fb2ea8533aeb6c265822acf312e7067/packages/pliny/src/mdx-plugins/remark-img-to-jsx.ts#L13</a></p><p><a href="https://github.com/facebook/docusaurus/blob/26ae4164d6f90c231c6687363a3907b5f9f172b8/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts#L160">https://github.com/facebook/docusaurus/blob/26ae4164d6f90c231c6687363a3907b5f9f172b8/packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts#L160</a></p><h2 id="netlify"><a href="#netlify" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Netlify</h2><p><a href="https://docs.netlify.com/configure-builds/manage-dependencies/#pnpm">https://docs.netlify.com/configure-builds/manage-dependencies/#pnpm</a></p><p>Netlify supports pnpm for Node.js 16.9.0 and later.</p><p>If your site’s base directory includes a pnpm-lock.yaml file, we will run pnpm install to install the dependencies listed in your package.json.</p><p>To specify a pnpm version, you can edit your package.json file:</p><p>&quot;packageManager&quot;: &quot;[email protected]&quot;</p><p>This tells Corepack to use and download your preferred pnpm version instead of the default version that Netlify sets.</p><p>In certain scenarios, you must pass additional flags to the pnpm install command. For example, some frameworks such as Nuxt 3 and Next.js require that you modify the pnpm install command. To avoid import issues with pnpm and these frameworks, use the <code>PNPM_FLAGS</code> environment variable and set it to <code>--shamefully-hoist</code>. Learn more in our Nuxt docs and Next.js docs.</p><p><a href="https://docs.netlify.com/integrations/frameworks/next-js/overview/#pnpm-support">https://docs.netlify.com/integrations/frameworks/next-js/overview/#pnpm-support</a></p><p>pnpm support If you’re planning to use pnpm with Next.js to manage dependencies, you must do one of the following:</p><p>Set a <code>PNPM_FLAGS</code> environment variable with a value of <code>--shamefully-hoist</code>. This appends a <code>--shamefully-hoist</code> argument to the pnpm install command that Netlify runs.</p><p>Enable public hoisting by adding an .npmrc file in the root of your project with this content:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token keyword">public</span><span class="token operator">-</span>hoist<span class="token operator">-</span>pattern<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">=</span><span class="token operator">*</span> </span></code></pre></div> Mon, 10 Jul 2023 13:08:12 GMT ttyS3 tailwindnext-jshugo https://ttys3.dev/blog/setup-chrome-policies-extensioninstallallowlist-under-linux Setup Chrome ExtensionInstallAllowlist Policies Under Linux https://ttys3.dev/blog/setup-chrome-policies-extensioninstallallowlist-under-linux <p>主要是想从 crx 文件安装一个<a href="https://github.com/pt-plugins/PT-Plugin-Plus/wiki/install-from-crx">扩展</a></p><p>因为一些原因, 这个扩展可能在 Chrome Web Store 上架的并不是最新版本, 所以只能从 crx 文件安装最新的版本.</p><p>但是当前 Chrome 版本已经不再允许直接从 crx 文件安装扩展了 (这里只讨论正常的安装, 不考虑打开开发者模式从文件load的情况).</p><p>不过 Chrome 官方也并没有封死路, 只是需要在策略里面添加一个白名单, 才能允许从 crx 文件安装扩展.</p><p>wiki里面只介绍了 Windows 下载改注册表的方法.</p><h2 id="windows-下的方法"><a href="#windows-下的方法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Windows 下的方法</h2><div class="relative"><pre><code class="code-highlight language-powershell"><span class="code-line"><span class="token comment"># Chrome</span> </span><span class="code-line">reg add HKLM\SOFTWARE\Policies\Google\Chrome\ExtensionInstallAllowlist <span class="token operator">/</span>v 99999 <span class="token operator">/</span>t reg_sz <span class="token operator">/</span>d dmmjlmbkigbgpnjfiimhlnbnmppjhpea <span class="token operator">/</span>f </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Edge</span> </span><span class="code-line">reg add HKLM\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallAllowlist <span class="token operator">/</span>v 99999 <span class="token operator">/</span>t reg_sz <span class="token operator">/</span>d dmmjlmbkigbgpnjfiimhlnbnmppjhpea <span class="token operator">/</span>f </span></code></pre></div><p>或将以下内容保存为 addWhitelist.reg 文件,然后双击导入注册表:</p><div class="relative"><pre><code class="code-highlight language-reg"><span class="code-line">Windows Registry Editor Version 5.00 </span><span class="code-line"> </span><span class="code-line">[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\ExtensionInstallAllowlist] </span><span class="code-line">&quot;99999&quot;=&quot;dmmjlmbkigbgpnjfiimhlnbnmppjhpea&quot; </span><span class="code-line">[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallAllowlist] </span><span class="code-line">&quot;99999&quot;=&quot;dmmjlmbkigbgpnjfiimhlnbnmppjhpea&quot; </span></code></pre></div><h2 id="linux-下的方法"><a href="#linux-下的方法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Linux 下的方法</h2><p>以 <code>ExtensionInstallAllowlist</code> 为关键字, 找到了一个文档: <a href="https://chromeenterprise.google/policies/#ExtensionInstallAllowlist">https://chromeenterprise.google/policies/#ExtensionInstallAllowlist</a></p><p>不过这个文档也比较抽象. 这个配置文件完整的结构是什么样的呢? 也没有个 demo. 不过最终老灯还是研究出来了方法. 记录如下.</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token comment"># 如果 /etc/opt/chrome/policies/managed 不存在, 则自己创建一下</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">mkdir</span> <span class="token parameter variable">-p</span> /etc/opt/chrome/policies/managed </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># edge linux stable is:</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">mkdir</span> <span class="token parameter variable">-p</span> /etc/opt/edge/policies/managed </span></code></pre></div><p>然后在 <code>/etc/opt/chrome/policies/managed</code> 下创建一个 <code>extension_install_allowlist.json</code> 文件 (文件名称随意), 内容如下:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;ExtensionInstallAllowlist&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&quot;dmmjlmbkigbgpnjfiimhlnbnmppjhpea&quot;</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>这个规则, Chrome 是动态加载的. 也就是说, 你可以随时修改这个文件, 就会即时生效.</p><p>要查看生效的策略, 可以访问: <code>chrome://policy/</code> , 如果看到 <code>ExtensionInstallAllowlist</code> 策略, 并且状态是 OK, 则说明策略配置正确且生效了.</p><p>for edge, access <code>edge://policy/</code></p><div><img alt="chrome-ext-install-allow-list-2022-12-22_23-40.png" src="https://ttys3.dev/static/assets/chrome-ext-install-allow-list-2022-12-22_23-40-LOT7RBVD.png" width="2533" height="589"/></div><p><code>dmmjlmbkigbgpnjfiimhlnbnmppjhpea</code> 是 Chrome 扩展的 ID, 关于怎么获取这个 ID, 官方有<a href="https://support.google.com/chrome/a/answer/7517525?hl=en">文档</a></p><p>但是其实这个东西很简单都不用说了, 就是 Chrome store 后面那一串字符串.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p>Set Chrome app and extension policies (Linux) <a href="https://support.google.com/chrome/a/answer/7517525?hl=en">https://support.google.com/chrome/a/answer/7517525?hl=en</a></p><p>ExtensionInstallAllowlist Configure extension installation allow list <a href="https://chromeenterprise.google/policies/#ExtensionInstallAllowlist">https://chromeenterprise.google/policies/#ExtensionInstallAllowlist</a></p> Thu, 22 Dec 2022 15:29:48 GMT ttyS3 ChromeExtensionInstallAllowlistLinuxPolicies https://ttys3.dev/blog/fixup-systemd-resolved-dns 修复 systemd resolved DNS 配置 https://ttys3.dev/blog/fixup-systemd-resolved-dns <h2 id="solution"><a href="#solution" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>solution</h2><p>其实是升级后 tailscale 提示我的.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ tailscale status </span><span class="code-line"><span class="token comment"># Health check:</span> </span><span class="code-line"><span class="token comment"># - dns-manager: systemd-resolved and NetworkManager are wired together incorrectly; MagicDNS will probably not work. For more info, see https://tailscale.com/s/resolved-nm</span> </span><span class="code-line"><span class="token comment"># - dns-os: setLinkDNS: Could not activate remote peer.</span> </span><span class="code-line"><span class="token comment"># - dns: setLinkDNS: Could not activate remote peer.</span> </span></code></pre></div><p><code>/etc/resolv.conf</code> 的内容虽然是正常的 <code>nameserver 127.0.0.53</code>, 但是这个文件并不是指向 systemd-resolved stub 的一个符号链接.</p><p>tailscale 检测出了这一问题. 其实产生这个问题的原因是, 我这台机器的 systemd-resolved 这个服务没有被启用 (有可能是突然断电造成的问题).</p><p>参考它的方法 <a href="https://tailscale.com/kb/1188/linux-dns/">https://tailscale.com/kb/1188/linux-dns/</a> 还不够. 我们需要启用 <code>systemd-resolved</code> 这个服务:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 以下操作均以 root 身份的执行</span> </span><span class="code-line"> </span><span class="code-line">systemctl <span class="token builtin class-name">enable</span> <span class="token variable parameter">--now</span> systemd-resolved </span><span class="code-line"> </span><span class="code-line"><span class="token function">ln</span> <span class="token variable parameter">-sf</span> /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf </span><span class="code-line"> </span><span class="code-line">systemctl restart systemd-resolved </span><span class="code-line">systemctl restart NetworkManager </span><span class="code-line">systemctl restart tailscaled </span></code></pre></div><h2 id="misc"><a href="#misc" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>misc</h2><p>MagicDNS 是 tailscale 推出的一个很方便的功能, 可以让你使用域名访问你的内网资源. 而不是 IP.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ resolvectl status tailscale0 </span><span class="code-line">Link <span class="token number">6</span> <span class="token punctuation">(</span>tailscale0<span class="token punctuation">)</span> </span><span class="code-line"> Current Scopes: DNS </span><span class="code-line"> Protocols: <span class="token variable parameter">-DefaultRoute</span> <span class="token variable parameter">-LLMNR</span> <span class="token variable parameter">-mDNS</span> <span class="token variable parameter">-DNSOverTLS</span> <span class="token variable assign-left">DNSSEC</span><span class="token operator">=</span>no/unsupported </span><span class="code-line">Current DNS Server: <span class="token number">100.100</span>.100.100 </span><span class="code-line"> DNS Servers: <span class="token number">100.100</span>.100.100 </span><span class="code-line"> DNS Domain: xxxxxxxxxxxxxxxxxxxx <span class="token punctuation">(</span>此处为敏感信息<span class="token punctuation">)</span> </span></code></pre></div><p>可以看到 <code>tailscale0</code> 的 DNS 在启用了 MagicDNS 后, 变成了 <code>100.100.100.100</code> , 它会负责解析 tailscale 相关的域名 (比如 hostname.xxxx.ts.net)</p> Mon, 07 Nov 2022 19:08:08 GMT ttyS3 tailscalednssystemdsystemd-resolvedMagicDNS https://ttys3.dev/blog/how-to-upgrade-centos-stream-8-to-stream-9 How to Upgrade CentOS Stream 8 to Stream 9 https://ttys3.dev/blog/how-to-upgrade-centos-stream-8-to-stream-9 <p>CS9 (CentOS Stream 9) 发布也挺久了.</p><p>一直没有升级, 主要是官方一直没有发布升级指南. 这一点 CentOS 比较坑 (当然, RHEL用户是可以从RHEL8 升级 RHEL9的).</p><p>reddit 上甚至有 RHEL 的员工回复:</p><p>Q: How to upgrade from Stream 8 to Stream 9? A:</p><blockquote><p>rbowen2000 1 yr. ago Red Hat Employee No. There is not currently a way to do an in-place upgrade between C8S and C9S, nor do we expect for there to be one. This is one of the questions that gets asked at each of our CentOS Dojo AMA sessions, and the answer is typically along the lines of &quot;Red Hat Engineering isn&#x27;t interested in this feature for RHEL, and so it won&#x27;t be worked on for CentOS. However, if someone from the community works on it, that would be awesome.&quot;</p><p>Related, the ELevate project - <a href="https://almalinux.org/elevate">https://almalinux.org/elevate</a> - may be the solution to this problem, but isn&#x27;t yet. I <em>think</em> that Jack suggested that upgrades between various CentOS Stream versions was a long-term goal.</p></blockquote><p>ref: <a href="https://www.reddit.com/r/CentOS/comments/ql5iek/how_to_upgrade_from_stream_8_to_stream_9/">https://www.reddit.com/r/CentOS/comments/ql5iek/how_to_upgrade_from_stream_8_to_stream_9/</a></p><p>其实这个回复具有很大的误导作用.</p><p>CS8 到 CS9 并不是不能升级, 而是, 从企业级的角度来看, 这个升级可能要花费很多时间去校验其可行性和稳定性, 以及各种包的兼容问题处理等.</p><p>当然, 对于个人用户来说, 这个升级完全是可行的.</p><p>我就一 NAS, 升挂了大不了我重装为 Fedora Server. (嗯,我之前是从 CentOS 8升级到 Stream 8 的, 如果早知道它会搞出 Stream, 我就直接装 Fedora Server了, 至少是发布的稳定版)</p><h2 id="升级步骤"><a href="#升级步骤" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>升级步骤</h2><p>以下操作都是在 root 用户下进行的.</p><ol><li>先升级 CS8 到最新版</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf upgrade <span class="token variable parameter">--refresh</span> <span class="token variable parameter">-y</span> </span></code></pre></div><ol start="2"><li>移除非必要RPM包 (没有被任何其它包依赖的包) 和 orphans 包 (当前的repo中已经不存在了的包)</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf remove <span class="token variable parameter">-y</span> <span class="token variable"><span class="token variable">$(</span>dnf repoquery <span class="token variable parameter">--unneeded</span><span class="token variable">)</span></span> </span><span class="code-line"> </span><span class="code-line">dnf remove <span class="token variable parameter">-y</span> <span class="token variable"><span class="token variable">$(</span>dnf repoquery <span class="token variable parameter">--extras</span><span class="token variable">)</span></span> </span><span class="code-line"> </span><span class="code-line">dnf autoremove <span class="token variable parameter">-y</span> </span></code></pre></div><ol start="3"><li>清理旧的内核 (可选操作)</li></ol><p>我们先看下当前的内核版本(主要是方便翻车后选择从这个旧内核启动):</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">uname</span> <span class="token variable parameter">-a</span> </span><span class="code-line">Linux homenas <span class="token number">4.18</span>.0-408.el8.x86_64 <span class="token comment">#1 SMP Mon Jul 18 17:42:52 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux</span> </span></code></pre></div><p>偷懒的清理方法是, 删除所有内核,然后再安装最新的内核:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">rpm</span> <span class="token variable parameter">-e</span> <span class="token variable"><span class="token variable">`</span><span class="token function">rpm</span> <span class="token variable parameter">-q</span> kernel<span class="token variable">`</span></span> <span class="token variable parameter">--nodeps</span> </span><span class="code-line"><span class="token function">rpm</span> <span class="token variable parameter">-e</span> <span class="token variable"><span class="token variable">`</span><span class="token function">rpm</span> <span class="token variable parameter">-q</span> kernel-devel<span class="token variable">`</span></span> <span class="token variable parameter">--nodeps</span> </span><span class="code-line"><span class="token function">rpm</span> <span class="token variable parameter">-e</span> <span class="token variable"><span class="token variable">`</span><span class="token function">rpm</span> <span class="token variable parameter">-q</span> kernel-core<span class="token variable">`</span></span> <span class="token variable parameter">--nodeps</span> </span><span class="code-line"><span class="token function">rpm</span> <span class="token variable parameter">-e</span> <span class="token variable"><span class="token variable">`</span><span class="token function">rpm</span> <span class="token variable parameter">-q</span> kernel-modules<span class="token variable">`</span></span> <span class="token variable parameter">--nodeps</span> </span><span class="code-line"> </span><span class="code-line">dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> kernel </span></code></pre></div><ol start="4"><li>下载 epel9 和 cs9 的 repo rpm 安装文件</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">mkdir</span> <span class="token variable parameter">-p</span> /root/upgrade/epel9 </span><span class="code-line"><span class="token builtin class-name">cd</span> /root/upgrade/epel9 </span><span class="code-line"> </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-9.noarch.rpm </span><span class="code-line"> </span><span class="code-line"><span class="token builtin class-name">cd</span> <span class="token punctuation">..</span>/ </span><span class="code-line"><span class="token comment"># http://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/Packages/ 找到最新的 centos-stream-release 和 centos-stream-repos 包下载回来</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> http://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/Packages/centos-stream-release-9.0-18.el9.noarch.rpm </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> http://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/Packages/centos-stream-repos-9.0-18.el9.noarch.rpm </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> http://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/Packages/centos-gpg-keys-9.0-18.el9.noarch.rpm </span></code></pre></div><ol start="5"><li>安装 epel9 和 cs9 的 repo rpm</li></ol><p>先安装 cs 9 rpm:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> *.rpm </span></code></pre></div><p>再安装 epel9:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token builtin class-name">cd</span> epel9 </span><span class="code-line">dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> *.rpm </span></code></pre></div><ol start="6"><li>升级到 CS9</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf <span class="token variable parameter">-y</span> <span class="token variable parameter">--releasever</span><span class="token operator">=</span><span class="token number">9</span> <span class="token variable parameter">--allowerasing</span> <span class="token variable parameter">--setopt</span><span class="token operator">=</span>deltarpm<span class="token operator">=</span>false distro-sync </span></code></pre></div><p>这里老灯遇到了个包冲突:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token punctuation">(</span><span class="token number">1116</span>/1116<span class="token punctuation">)</span>: isl-0.16.1-15.el9.x86_64.rpm <span class="token number">16</span> kB/s <span class="token operator">|</span> <span class="token number">864</span> kB 00:53 </span><span class="code-line">---------------------------------------------------------------------------------------------------------- </span><span class="code-line">Total <span class="token number">12</span> MB/s <span class="token operator">|</span> <span class="token number">1.2</span> GB 01:46 </span><span class="code-line">Extra Packages <span class="token keyword">for</span> Enterprise Linux <span class="token number">9</span> - x86_64 <span class="token number">1.6</span> MB/s <span class="token operator">|</span> <span class="token number">1.6</span> kB 00:00 </span><span class="code-line">Importing GPG key 0x3228467C: </span><span class="code-line"> Userid <span class="token builtin class-name">:</span> <span class="token string">&quot;Fedora (epel9) &lt;[email protected]&gt;&quot;</span> </span><span class="code-line"> Fingerprint: FF8A D134 <span class="token number">4597</span> 106E CE81 3B91 8A38 72BF <span class="token number">3228</span> 467C </span><span class="code-line"> From <span class="token builtin class-name">:</span> /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 </span><span class="code-line">Key imported successfully </span><span class="code-line">Running transaction check </span><span class="code-line">Transaction check succeeded. </span><span class="code-line">Running transaction <span class="token builtin class-name">test</span> </span><span class="code-line">The downloaded packages were saved <span class="token keyword">in</span> cache <span class="token keyword">until</span> the next successful transaction. </span><span class="code-line">You can remove cached packages by executing <span class="token string">&#x27;dnf clean packages&#x27;</span><span class="token builtin class-name">.</span> </span><span class="code-line">Error: Transaction <span class="token builtin class-name">test</span> error: </span><span class="code-line"> <span class="token function">file</span> /usr/share/terminfo/r/rxvt-unicode-256color from <span class="token function">install</span> of ncurses-base-6.2-8.20210508.el9.noarch conflicts with <span class="token function">file</span> from package rxvt-unicode-terminfo-9.26-1.el8.noarch </span></code></pre></div><p>解决方法是直接 <code>dnf remove rxvt-unicode-terminfo-9.26-1.el8 -y</code> 即可.</p><p>然后再重新执行上面的升级语句.</p><ol start="7"><li>重建 rpm 数据库</li></ol><p>这里需要重建的原因主要是: CS9 的 rpm 数据库格式从 bdb_ro 变成了 sqlite</p><p>ref <a href="https://fedoraproject.org/wiki/Changes/Sqlite_Rpmdb">https://fedoraproject.org/wiki/Changes/Sqlite_Rpmdb</a></p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">rpmdb <span class="token variable parameter">--rebuilddb</span> </span></code></pre></div><ol start="8"><li>清理 dnf 缓存 (可选操作)</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf clean packages </span></code></pre></div><p><code>subscription-manager</code> 这个包一般人也用不到订阅, 可以卸载: <code>dnf remove -y subscription-manager</code></p><ol start="9"><li>再升级一次</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf upgrade <span class="token variable parameter">--refresh</span> <span class="token variable parameter">-y</span> </span></code></pre></div><ol start="10"><li>确保核心包已安装</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf <span class="token variable parameter">-y</span> groupupdate <span class="token string">&quot;Core&quot;</span> <span class="token string">&quot;Minimal Install&quot;</span> </span></code></pre></div><ol start="11"><li>检查内核和 sshd 是否安装成功</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">检查默认启动内核: </span><span class="code-line"> </span><span class="code-line">❯ grubby --default-kernel </span><span class="code-line">/boot/vmlinuz-5.14.0-183.el9.x86_64 </span><span class="code-line"> </span><span class="code-line">检查内核和 sshd 是否安装成功 </span><span class="code-line"> </span><span class="code-line">❯ dnf list <span class="token variable parameter">--installed</span> <span class="token operator">|</span> rg <span class="token function">ssh</span> </span><span class="code-line">libssh.x86_64 <span class="token number">0.10</span>.4-3.el9 @baseos </span><span class="code-line">libssh-config.noarch <span class="token number">0.10</span>.4-3.el9 @baseos </span><span class="code-line">openssh.x86_64 <span class="token number">8</span>.7p1-24.el9 @baseos </span><span class="code-line">openssh-clients.x86_64 <span class="token number">8</span>.7p1-24.el9 @baseos </span><span class="code-line">openssh-server.x86_64 <span class="token number">8</span>.7p1-24.el9 @baseos </span><span class="code-line"> </span><span class="code-line">❯ dnf list <span class="token variable parameter">--installed</span> <span class="token operator">|</span> rg kernel </span><span class="code-line">kernel.x86_64 <span class="token number">4.18</span>.0-408.el8 @baseos </span><span class="code-line">kernel.x86_64 <span class="token number">5.14</span>.0-183.el9 @baseos </span><span class="code-line">kernel-core.x86_64 <span class="token number">4.18</span>.0-408.el8 @baseos </span><span class="code-line">kernel-core.x86_64 <span class="token number">5.14</span>.0-183.el9 @baseos </span><span class="code-line">kernel-devel.x86_64 <span class="token number">4.18</span>.0-408.el8 @baseos </span><span class="code-line">kernel-devel.x86_64 <span class="token number">5.14</span>.0-183.el9 @appstream </span><span class="code-line">kernel-devel-matched.x86_64 <span class="token number">5.14</span>.0-183.el9 @appstream </span><span class="code-line">kernel-headers.x86_64 <span class="token number">5.14</span>.0-183.el9 @appstream </span><span class="code-line">kernel-modules.x86_64 <span class="token number">4.18</span>.0-408.el8 @baseos </span><span class="code-line">kernel-modules.x86_64 <span class="token number">5.14</span>.0-183.el9 @baseos </span><span class="code-line">kernel-srpm-macros.noarch <span class="token number">1.0</span>-11.el9 @appstream </span><span class="code-line">kernel-tools.x86_64 <span class="token number">5.14</span>.0-183.el9 @baseos </span><span class="code-line">kernel-tools-libs.x86_64 <span class="token number">5.14</span>.0-183.el9 @baseos </span></code></pre></div><ol start="12"><li>重启</li></ol><p>重启比较快, 整个升级还算是比较成功的.</p><p>检查当前的版本是不是已经升级到 CS9 了:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">cat</span> /etc/os-release </span><span class="code-line"><span class="token variable assign-left">NAME</span><span class="token operator">=</span><span class="token string">&quot;CentOS Stream&quot;</span> </span><span class="code-line"><span class="token variable assign-left">VERSION</span><span class="token operator">=</span><span class="token string">&quot;9&quot;</span> </span><span class="code-line"><span class="token variable assign-left">ID</span><span class="token operator">=</span><span class="token string">&quot;centos&quot;</span> </span><span class="code-line"><span class="token variable assign-left">ID_LIKE</span><span class="token operator">=</span><span class="token string">&quot;rhel fedora&quot;</span> </span><span class="code-line"><span class="token variable assign-left">VERSION_ID</span><span class="token operator">=</span><span class="token string">&quot;9&quot;</span> </span><span class="code-line"><span class="token variable assign-left">PLATFORM_ID</span><span class="token operator">=</span><span class="token string">&quot;platform:el9&quot;</span> </span><span class="code-line"><span class="token variable assign-left">PRETTY_NAME</span><span class="token operator">=</span><span class="token string">&quot;CentOS Stream 9&quot;</span> </span><span class="code-line"><span class="token variable assign-left">ANSI_COLOR</span><span class="token operator">=</span><span class="token string">&quot;0;31&quot;</span> </span><span class="code-line"><span class="token variable assign-left">LOGO</span><span class="token operator">=</span><span class="token string">&quot;fedora-logo-icon&quot;</span> </span><span class="code-line"><span class="token variable assign-left">CPE_NAME</span><span class="token operator">=</span><span class="token string">&quot;cpe:/o:centos:centos:9&quot;</span> </span><span class="code-line"><span class="token variable assign-left">HOME_URL</span><span class="token operator">=</span><span class="token string">&quot;https://centos.org/&quot;</span> </span><span class="code-line"><span class="token variable assign-left">BUG_REPORT_URL</span><span class="token operator">=</span><span class="token string">&quot;https://bugzilla.redhat.com/&quot;</span> </span><span class="code-line"><span class="token variable assign-left">REDHAT_SUPPORT_PRODUCT</span><span class="token operator">=</span><span class="token string">&quot;Red Hat Enterprise Linux 9&quot;</span> </span><span class="code-line"><span class="token variable assign-left">REDHAT_SUPPORT_PRODUCT_VERSION</span><span class="token operator">=</span><span class="token string">&quot;CentOS Stream&quot;</span> </span></code></pre></div><p>检查内核版本:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">uname</span> <span class="token variable parameter">-a</span> </span><span class="code-line">Linux homenas <span class="token number">5.14</span>.0-183.el9.x86_64 <span class="token comment">#1 SMP PREEMPT_DYNAMIC Mon Oct 31 09:18:51 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux</span> </span></code></pre></div><h2 id="其它清理"><a href="#其它清理" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它清理</h2><p>确认启动工作正常后, 可以把旧的内核删除了.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">rpm</span> <span class="token variable parameter">-q</span> kernel-core </span><span class="code-line">kernel-core-4.18.0-408.el8.x86_64 </span><span class="code-line">kernel-core-5.14.0-183.el9.x86_64 </span></code></pre></div><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf remove <span class="token variable parameter">-y</span> kernel-core-4.18.0-408.el8 </span></code></pre></div><p>列出当前还在的安装自 CentOS Stream 8 的包:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ dnf list --installed<span class="token operator">|</span><span class="token function">grep</span> el8 </span><span class="code-line">bind-export-libs.x86_64 <span class="token number">32</span>:9.11.36-5.el8 @baseos </span><span class="code-line">bpytop.noarch <span class="token number">1</span>:1.0.54-3.el8 @epel </span><span class="code-line">cgdcbxd.x86_64 <span class="token number">1.0</span>.2-9.el8 @AppStream </span><span class="code-line">cri-o.x86_64 <span class="token number">1.22</span>.5-2.2.el8 @devel_kubic_libcontainers_stable_cri-o_1.22 </span><span class="code-line">iptstate.x86_64 <span class="token number">2.2</span>.6-6.el8 @anaconda </span><span class="code-line">iwl6000-firmware.noarch <span class="token number">9.221</span>.4.1-110.el8.1 @baseos </span><span class="code-line">javapackages-filesystem.noarch <span class="token number">5.3</span>.0-1.module_el8.0.0+11+5b8c10bd @AppStream </span><span class="code-line">kernel-devel.x86_64 <span class="token number">4.18</span>.0-408.el8 @baseos </span><span class="code-line">libXxf86misc.x86_64 <span class="token number">1.0</span>.4-1.el8 @AppStream </span><span class="code-line">libatomic_ops.x86_64 <span class="token number">7.6</span>.2-3.el8 @AppStream </span><span class="code-line">libcgroup.x86_64 <span class="token number">0.41</span>-19.el8 @anaconda </span><span class="code-line">libcroco.x86_64 <span class="token number">0.6</span>.12-4.el8_2.1 @anaconda </span><span class="code-line">libertas-usb8388-firmware.noarch <span class="token number">2</span>:20220726-110.git150864a4.el8 @baseos </span><span class="code-line">libmcpp.x86_64 <span class="token number">2.7</span>.2-20.el8 @AppStream </span><span class="code-line">libmodman.x86_64 <span class="token number">2.0</span>.1-17.el8 @anaconda </span><span class="code-line">man-pages-overrides.noarch <span class="token number">8.6</span>.0.0-1.el8 @appstream </span><span class="code-line">mcpp.x86_64 <span class="token number">2.7</span>.2-20.el8 @AppStream </span><span class="code-line">mozjs60.x86_64 <span class="token number">60.9</span>.0-4.el8 @anaconda </span><span class="code-line">openwsman-client.x86_64 <span class="token number">2.6</span>.5-9.el8 @appstream </span><span class="code-line">python38-pip-wheel.noarch <span class="token number">19.3</span>.1-6.module_el8.7.0+1184+30eba247 @appstream </span><span class="code-line">python38-setuptools-wheel.noarch <span class="token number">41.6</span>.0-5.module_el8.6.0+929+89303463 @appstream </span><span class="code-line">shim-x64.x86_64 <span class="token number">15</span>-15.el8_2 @anaconda </span><span class="code-line">terminus-fonts-console.noarch <span class="token number">4.48</span>-1.el8 @epel </span><span class="code-line">wireguard-dkms.noarch <span class="token number">1</span>:1.0.20220627-1.el8 @copr:copr.fedorainfracloud.org:jdoss:wireguard </span><span class="code-line">xorg-x11-font-utils.x86_64 <span class="token number">1</span>:7.5-41.el8 @appstream </span></code></pre></div><p>注意, 这里有些包不能直接 <code>dnf remove </code>卸载, 比如:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ dnf info kernel-devel </span><span class="code-line">Last metadata expiration check: <span class="token number">1</span>:58:17 ago on Tue 08 Nov <span class="token number">2022</span> 01:35:37 AM CST. </span><span class="code-line">Installed Packages </span><span class="code-line">Name <span class="token builtin class-name">:</span> kernel-devel </span><span class="code-line">Version <span class="token builtin class-name">:</span> <span class="token number">4.18</span>.0 </span><span class="code-line">Release <span class="token builtin class-name">:</span> <span class="token number">408</span>.el8 </span><span class="code-line">Architecture <span class="token builtin class-name">:</span> x86_64 </span><span class="code-line">Size <span class="token builtin class-name">:</span> <span class="token number">52</span> M </span><span class="code-line">Source <span class="token builtin class-name">:</span> kernel-4.18.0-408.el8.src.rpm </span><span class="code-line">Repository <span class="token builtin class-name">:</span> @System </span><span class="code-line">From repo <span class="token builtin class-name">:</span> baseos </span><span class="code-line">Summary <span class="token builtin class-name">:</span> Development package <span class="token keyword">for</span> building kernel modules to match the kernel </span><span class="code-line">URL <span class="token builtin class-name">:</span> http://www.kernel.org/ </span><span class="code-line">License <span class="token builtin class-name">:</span> GPLv2 and Redistributable, no modification permitted </span><span class="code-line">Description <span class="token builtin class-name">:</span> This package provides kernel headers and makefiles sufficient to build modules </span><span class="code-line"> <span class="token builtin class-name">:</span> against the kernel package. </span><span class="code-line"> </span><span class="code-line">Name <span class="token builtin class-name">:</span> kernel-devel </span><span class="code-line">Version <span class="token builtin class-name">:</span> <span class="token number">5.14</span>.0 </span><span class="code-line">Release <span class="token builtin class-name">:</span> <span class="token number">183</span>.el9 </span><span class="code-line">Architecture <span class="token builtin class-name">:</span> x86_64 </span><span class="code-line">Size <span class="token builtin class-name">:</span> <span class="token number">61</span> M </span><span class="code-line">Source <span class="token builtin class-name">:</span> kernel-5.14.0-183.el9.src.rpm </span><span class="code-line">Repository <span class="token builtin class-name">:</span> @System </span><span class="code-line">From repo <span class="token builtin class-name">:</span> appstream </span><span class="code-line">Summary <span class="token builtin class-name">:</span> Development package <span class="token keyword">for</span> building kernel modules to match the kernel </span><span class="code-line">URL <span class="token builtin class-name">:</span> https://www.kernel.org/ </span><span class="code-line">License <span class="token builtin class-name">:</span> GPLv2 and Redistributable, no modification permitted </span><span class="code-line">Description <span class="token builtin class-name">:</span> This package provides kernel headers and makefiles sufficient to build modules </span><span class="code-line"> <span class="token builtin class-name">:</span> against the kernel package. </span></code></pre></div><p>我们不是要卸载 <code>kernel-devel</code>, 而是只要卸载 <code>kernel-devel-4.18.0-408.el8</code>:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf remove kernel-devel-4.18.0-408.el8 </span></code></pre></div><p><code>terminus-fonts-console</code> 不要卸载, epel9 里面没有了. 这个只是个字体包, 不影响系统.</p><p><a href="https://packages.fedoraproject.org/pkgs/terminus-fonts/terminus-fonts-console/epel-8.html">https://packages.fedoraproject.org/pkgs/terminus-fonts/terminus-fonts-console/epel-8.html</a></p><p>不过没关系, 卸载了也可以安装回来:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> https://download-ib01.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/t/terminus-fonts-console-4.48-1.el8.noarch.rpm </span></code></pre></div><h2 id="其它"><a href="#其它" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它</h2><p>升级过程中会有一些警告信息, 目前看来没有什么影响.</p><p>信息1:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token operator">/</span>usr<span class="token operator">/</span>sbin<span class="token operator">/</span>ldconfig<span class="token operator">:</span> <span class="token operator">/</span>lib64<span class="token operator">/</span>ld<span class="token operator">-</span>linux<span class="token operator">-</span>x86<span class="token operator">-</span><span class="token number">64</span><span class="token punctuation">.</span><span class="token property-access">so</span><span class="token punctuation">.</span><span class="token number">2</span> is not a symbolic link </span><span class="code-line"> </span><span class="code-line"><span class="token operator">/</span>sbin<span class="token operator">/</span>ldconfig<span class="token operator">:</span> <span class="token operator">/</span>lib64<span class="token operator">/</span>ld<span class="token operator">-</span>linux<span class="token operator">-</span>x86<span class="token operator">-</span><span class="token number">64</span><span class="token punctuation">.</span><span class="token property-access">so</span><span class="token punctuation">.</span><span class="token number">2</span> is not a symbolic link </span><span class="code-line"> </span><span class="code-line"><span class="token operator">/</span>sbin<span class="token operator">/</span>ldconfig<span class="token operator">:</span> <span class="token operator">/</span>lib64<span class="token operator">/</span>libslapi<span class="token operator">-</span><span class="token number">2.4</span><span class="token punctuation">.</span><span class="token property-access">so</span><span class="token punctuation">.</span><span class="token number">2</span> is not a symbolic link </span><span class="code-line"> </span><span class="code-line"><span class="token operator">/</span>sbin<span class="token operator">/</span>ldconfig<span class="token operator">:</span> <span class="token operator">/</span>lib64<span class="token operator">/</span>libldap_r<span class="token operator">-</span><span class="token number">2.4</span><span class="token punctuation">.</span><span class="token property-access">so</span><span class="token punctuation">.</span><span class="token number">2</span> is not a symbolic link </span><span class="code-line"> </span><span class="code-line"><span class="token operator">/</span>sbin<span class="token operator">/</span>ldconfig<span class="token operator">:</span> <span class="token operator">/</span>lib64<span class="token operator">/</span>libldap<span class="token operator">-</span><span class="token number">2.4</span><span class="token punctuation">.</span><span class="token property-access">so</span><span class="token punctuation">.</span><span class="token number">2</span> is not a symbolic link </span><span class="code-line"> </span><span class="code-line"><span class="token operator">/</span>sbin<span class="token operator">/</span>ldconfig<span class="token operator">:</span> <span class="token operator">/</span>lib64<span class="token operator">/</span>liblber<span class="token operator">-</span><span class="token number">2.4</span><span class="token punctuation">.</span><span class="token property-access">so</span><span class="token punctuation">.</span><span class="token number">2</span> is not a symbolic link </span><span class="code-line"> </span><span class="code-line"><span class="token operator">/</span>sbin<span class="token operator">/</span>ldconfig<span class="token operator">:</span> <span class="token operator">/</span>lib64<span class="token operator">/</span>ld<span class="token operator">-</span>linux<span class="token operator">-</span>x86<span class="token operator">-</span><span class="token number">64</span><span class="token punctuation">.</span><span class="token property-access">so</span><span class="token punctuation">.</span><span class="token number">2</span> is not a symbolic link </span></code></pre></div><p>信息2:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">failed to link <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>python3 <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives<span class="token operator">/</span>python3<span class="token operator">:</span> <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>python3 exists and it is either not a symlink or <span class="token operator">--</span>keep<span class="token operator">-</span>foreign was <span class="token keyword">set</span> and link points outside <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives </span><span class="code-line">failed to link <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>pip<span class="token operator">-</span><span class="token number">3</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives<span class="token operator">/</span>pip<span class="token operator">-</span><span class="token number">3</span><span class="token operator">:</span> <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>pip<span class="token operator">-</span><span class="token number">3</span> exists and it is either not a symlink or <span class="token operator">--</span>keep<span class="token operator">-</span>foreign was <span class="token keyword">set</span> and link points outside <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives </span><span class="code-line">failed to link <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>pip3 <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives<span class="token operator">/</span>pip3<span class="token operator">:</span> <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>pip3 exists and it is either not a symlink or <span class="token operator">--</span>keep<span class="token operator">-</span>foreign was <span class="token keyword">set</span> and link points outside <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives </span><span class="code-line">failed to link <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>pydoc3 <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives<span class="token operator">/</span>pydoc3<span class="token operator">:</span> <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>pydoc3 exists and it is either not a symlink or <span class="token operator">--</span>keep<span class="token operator">-</span>foreign was <span class="token keyword">set</span> and link points outside <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives </span><span class="code-line">failed to link <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>python3<span class="token operator">-</span>config <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives<span class="token operator">/</span>python3<span class="token operator">-</span>config<span class="token operator">:</span> <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>python3<span class="token operator">-</span>config exists and it is either not a symlink or <span class="token operator">--</span>keep<span class="token operator">-</span>foreign was <span class="token keyword">set</span> and link points outside <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives </span><span class="code-line">failed to link <span class="token operator">/</span>usr<span class="token operator">/</span>share<span class="token operator">/</span>man<span class="token operator">/</span>man1<span class="token operator">/</span>python3<span class="token punctuation">.</span><span class="token number">1</span><span class="token punctuation">.</span><span class="token property-access">gz</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives<span class="token operator">/</span>python3<span class="token operator">-</span>man<span class="token operator">:</span> <span class="token operator">/</span>usr<span class="token operator">/</span>share<span class="token operator">/</span>man<span class="token operator">/</span>man1<span class="token operator">/</span>python3<span class="token punctuation">.</span><span class="token number">1</span><span class="token punctuation">.</span><span class="token property-access">gz</span> exists and it is either not a symlink or <span class="token operator">--</span>keep<span class="token operator">-</span>foreign was <span class="token keyword">set</span> and link points outside <span class="token operator">/</span>etc<span class="token operator">/</span>alternatives </span></code></pre></div><p>另外还有一些配置升级的信息:</p><p>只要软件没有破坏性变更, 这些配置不 migration 一般也没事.</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token literal-property property">warning</span><span class="token operator">:</span> <span class="token operator">/</span>etc<span class="token operator">/</span>nsswitch<span class="token punctuation">.</span><span class="token property-access">conf</span> created <span class="token keyword module">as</span> <span class="token operator">/</span>etc<span class="token operator">/</span>nsswitch<span class="token punctuation">.</span><span class="token property-access">conf</span><span class="token punctuation">.</span><span class="token property-access">rpmnew</span> </span><span class="code-line"> </span><span class="code-line"><span class="token literal-property property">warning</span><span class="token operator">:</span> <span class="token operator">/</span>etc<span class="token operator">/</span>systemd<span class="token operator">/</span>system<span class="token punctuation">.</span><span class="token property-access">conf</span> created <span class="token keyword module">as</span> <span class="token operator">/</span>etc<span class="token operator">/</span>systemd<span class="token operator">/</span>system<span class="token punctuation">.</span><span class="token property-access">conf</span><span class="token punctuation">.</span><span class="token property-access">rpmnew</span> </span><span class="code-line"> </span><span class="code-line"><span class="token literal-property property">warning</span><span class="token operator">:</span> <span class="token operator">/</span>etc<span class="token operator">/</span>samba<span class="token operator">/</span>smb<span class="token punctuation">.</span><span class="token property-access">conf</span> created <span class="token keyword module">as</span> <span class="token operator">/</span>etc<span class="token operator">/</span>samba<span class="token operator">/</span>smb<span class="token punctuation">.</span><span class="token property-access">conf</span><span class="token punctuation">.</span><span class="token property-access">rpmnew</span> </span><span class="code-line"> </span><span class="code-line"><span class="token literal-property property">warning</span><span class="token operator">:</span> <span class="token operator">/</span>etc<span class="token operator">/</span>systemd<span class="token operator">/</span>resolved<span class="token punctuation">.</span><span class="token property-access">conf</span> created <span class="token keyword module">as</span> <span class="token operator">/</span>etc<span class="token operator">/</span>systemd<span class="token operator">/</span>resolved<span class="token punctuation">.</span><span class="token property-access">conf</span><span class="token punctuation">.</span><span class="token property-access">rpmnew</span> </span><span class="code-line"> </span><span class="code-line"><span class="token literal-property property">warning</span><span class="token operator">:</span> <span class="token operator">/</span>etc<span class="token operator">/</span>containers<span class="token operator">/</span>registries<span class="token punctuation">.</span><span class="token property-access">conf</span> created <span class="token keyword module">as</span> <span class="token operator">/</span>etc<span class="token operator">/</span>containers<span class="token operator">/</span>registries<span class="token punctuation">.</span><span class="token property-access">conf</span><span class="token punctuation">.</span><span class="token property-access">rpmnew</span> </span><span class="code-line"> </span><span class="code-line"><span class="token literal-property property">warning</span><span class="token operator">:</span> <span class="token operator">/</span>etc<span class="token operator">/</span>chrony<span class="token punctuation">.</span><span class="token property-access">conf</span> created <span class="token keyword module">as</span> <span class="token operator">/</span>etc<span class="token operator">/</span>chrony<span class="token punctuation">.</span><span class="token property-access">conf</span><span class="token punctuation">.</span><span class="token property-access">rpmnew</span> </span></code></pre></div><p><code>/etc/yum.repos.d</code> 残余的 cs8 repo 文件问题: 其实我是在升级之前备份, 然后手动删除了这些 xxx.repo 文件的, 但是升级完后会有这些警告信息.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ dnf module list </span><span class="code-line">Last metadata expiration check: <span class="token number">0</span>:10:14 ago on Tue 08 Nov <span class="token number">2022</span> <span class="token number">12</span>:58:15 AM CST. </span><span class="code-line">Modular dependency problems: </span><span class="code-line"> </span><span class="code-line"> Problem <span class="token number">1</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:el8<span class="token punctuation">)</span> needed by module nodejs:14:8070020220601142310:3b9f49c4.x86_64 </span><span class="code-line"> Problem <span class="token number">2</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:el8<span class="token punctuation">)</span> needed by module perl-DBD-SQLite:1.58:8030020200716174729:3a70019f.x86_64 </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>perl:5.26<span class="token punctuation">)</span> needed by module perl-DBD-SQLite:1.58:8030020200716174729:3a70019f.x86_64 </span><span class="code-line"> Problem <span class="token number">3</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:el8<span class="token punctuation">)</span> needed by module perl-DBI:1.641:8030020200716150652:1e4bbb35.x86_64 </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>perl:5.26<span class="token punctuation">)</span> needed by module perl-DBI:1.641:8030020200716150652:1e4bbb35.x86_64 </span><span class="code-line"> Problem <span class="token number">4</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:el8<span class="token punctuation">)</span> needed by module perl-IO-Socket-SSL:2.066:8040020200924212038:1aedcbfe.x86_64 </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>perl:5.26<span class="token punctuation">)</span> needed by module perl-IO-Socket-SSL:2.066:8040020200924212038:1aedcbfe.x86_64 </span><span class="code-line"> Problem <span class="token number">5</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:el8<span class="token punctuation">)</span> needed by module perl-libwww-perl:6.34:8040020211102170116:bf75fe78.x86_64 </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>perl:5.26<span class="token punctuation">)</span> needed by module perl-libwww-perl:6.34:8040020211102170116:bf75fe78.x86_64 </span><span class="code-line"> Problem <span class="token number">6</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:el8<span class="token punctuation">)</span> needed by module python36:3.6:8050020210825152031:982725ab.x86_64 </span><span class="code-line"> Problem <span class="token number">7</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:el8<span class="token punctuation">)</span> needed by module python38:3.8:8070020220920211024:bd194b04.x86_64 </span><span class="code-line"> Problem <span class="token number">8</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:el8<span class="token punctuation">)</span> needed by module virt:rhel:8070020220921151759:3b9f49c4.x86_64 </span></code></pre></div><p>解决办法:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf module reset nodejs perl-DBD-SQLite perl-DBI perl-IO-Socket-SSL perl-libwww-perl python36 python38 virt </span></code></pre></div><p>然后再执行 <code>dnf module list</code> 就没有问题了:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ dnf module list </span><span class="code-line">Last metadata expiration check: <span class="token number">0</span>:10:51 ago on Tue 08 Nov <span class="token number">2022</span> <span class="token number">12</span>:58:15 AM CST. </span><span class="code-line">@modulefailsafe </span><span class="code-line">Name Stream Profiles Summary </span><span class="code-line">javapackages-runtime <span class="token number">201801</span> <span class="token punctuation">[</span>e<span class="token punctuation">]</span> common Basic runtime utilities to support Java applications </span><span class="code-line"> </span><span class="code-line">CentOS Stream <span class="token number">9</span> - AppStream </span><span class="code-line">Name Stream Profiles Summary </span><span class="code-line">maven <span class="token number">3.8</span> common <span class="token punctuation">[</span>d<span class="token punctuation">]</span> Java project management and project comprehension tool </span><span class="code-line">nodejs <span class="token number">18</span> common <span class="token punctuation">[</span>d<span class="token punctuation">]</span>, development, minimal, s2i Javascript runtime </span><span class="code-line">php <span class="token number">8.1</span> common <span class="token punctuation">[</span>d<span class="token punctuation">]</span>, devel, minimal PHP scripting language </span><span class="code-line">ruby <span class="token number">3.1</span> common <span class="token punctuation">[</span>d<span class="token punctuation">]</span> An interpreter of object-oriented scripting language </span><span class="code-line"> </span><span class="code-line">Hint: <span class="token punctuation">[</span>d<span class="token punctuation">]</span>efault, <span class="token punctuation">[</span>e<span class="token punctuation">]</span>nabled, <span class="token punctuation">[</span>x<span class="token punctuation">]</span>disabled, <span class="token punctuation">[</span>i<span class="token punctuation">]</span>nstalled </span></code></pre></div><p>可以看到 CS9 的 module 比 CS8 少很多.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p>主要参考 <a href="https://ahelpme.com/linux/centos-stream-9/how-to-upgrade-to-centos-stream-9-from-centos-stream-8/">https://ahelpme.com/linux/centos-stream-9/how-to-upgrade-to-centos-stream-9-from-centos-stream-8/</a></p><p><a href="https://github.com/Ink-33/OhMyStream9">https://github.com/Ink-33/OhMyStream9</a></p> Mon, 07 Nov 2022 18:34:52 GMT ttyS3 CentOS StreamCentOSupgradeCentOS-Stream-9 https://ttys3.dev/blog/o-reilly-learning-say-goodbye-to-acm ACM 会员已无 O'Reilly Learning 羊毛可撸 https://ttys3.dev/blog/o-reilly-learning-say-goodbye-to-acm <h2 id="缘由"><a href="#缘由" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h2><p>其实是 O&#x27;Reilly Learning 终止了和 ACM 合作.</p><p>毕竟 499刀的会员, 几十美元买个 ACM 会员就能白得. O&#x27;Reilly 估计觉得这已经影响到它自己卖 O&#x27;Reilly Learning 会员了.</p><p>这无疑是 ACM 的损失, 也是我们这些羊毛党的损失.</p><p>没有了 免费 O&#x27;Reilly Learning 资料库的 ACM 会员对于我来说, 毫无用处.</p><p><a href="https://web.archive.org/web/20220702061717/https://learning.acm.org/e-learning/oreilly">https://web.archive.org/web/20220702061717/https://learning.acm.org/e-learning/oreilly</a></p><p>Use promo code ACM10022 to receive an introductory one-year subscription for $399 (plus VAT/Tax).</p><p>这里搞笑的是, 我是今天收到了 O&#x27;Reilly Learning 有 299刀的优惠价的时候才想起了要说一下这事.</p><p>为什么呢? O&#x27;Reilly Learning 终止了和 ACM 合作 是今年(2022)年7月份的事. 当时给了 $399 刀一年的优惠价.</p><p>我现在庆幸当时没有买. 因为买了的话现在肯定会很郁闷. 给 ACM 的是 便宜 100 刀, 现在自家在促销, 便宜 200刀.</p><p>因为白嫖没有了, pku bbs 也有人讨论这个 <a href="https://bbs.pku.edu.cn/v2/post-read.php?bid=25&amp;threadid=18257725&amp;page=a&amp;postid=25437482">https://bbs.pku.edu.cn/v2/post-read.php?bid=25&amp;threadid=18257725&amp;page=a&amp;postid=25437482</a></p><blockquote><p>我是看到不少人吐槽ACM会员没法白嫖之后才知道这个数据库的😂有一说一这数据库确实很让我心动,如果不是这么贵我都考虑个人订阅了tokamako (1601213993) 在 ta 的帖子中提到:我猜大家都是因为 ACM 的会员没法白嫖 O&#x27;Reilly 的电子书了 XD</p></blockquote><p>他们讨论, 也许是因为清华已经订阅了 O&#x27;Reilly for Higher Education 吧: <a href="https://ecollection.lib.tsinghua.edu.cn/databasenav/entrance/detail?mmsid=991021796739403966">https://ecollection.lib.tsinghua.edu.cn/databasenav/entrance/detail?mmsid=991021796739403966</a></p><blockquote><p>资源简介 收录了2013以来出版的43,000多种电子图书(至2020年6月);7500多个视频,时长达到3万多个小时。资源类型包括电子书、视频、经典案例、在线教程(Tutorials)、学习路径等。资源数量持续增加。学习路径:来自基于多个主题的内容,包括分析、计算机网络、硬件、数据库、设计、数字媒体、教育等方面;在线教程(Oriole Online Tutorials):Oriole是一种新媒体,将代码,数据,文本和培训视频融合到整个学习体验中。读者可在实际操作中学习,提供互动编码环境,并且可以按照自身安排与进度进行学习。O’Reilly独家出版的汇集了商业与技术领域,源自世界著名创新者与企业负责人的最新专业知识、独家会议资源等:包括前美国白宫数据科学家D.J. Patil、前通用电气公司董事长兼首席执行官Jeff Immelt 、哈佛商学院商业管理教授Clayton M. Christensen、对冲基金Two Sigma执行总监Camille Fournier,及美国著名硅谷企业家 Eric Ries等。O’Reilly Media公司于2017年底,发布了新学习平台,整合了全球200多家世界知名出版社,例如Wiley,Pearson,O&#x27;Reilly, Packt Publishing,Infinite Skills,Stone River eLearning等。</p></blockquote><blockquote><p>特别提示 使用计算机可在线阅读,图书内容不能下载,但可以复制和单页打印。持续打印数量过大,会收到系统警告。</p></blockquote><h2 id="商家的套路"><a href="#商家的套路" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>商家的套路</h2><p>在 9-22 之前我收到的是这样的:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token maybe-class-name">If</span> you’ve been thinking about becoming an <span class="token constant">O</span>’Reilly member<span class="token punctuation">,</span> now’s the time to act<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">Join</span></span> before <span class="token maybe-class-name">September</span> <span class="token number">22</span> and <span class="token keyword">get</span> a year <span class="token keyword">of</span> <span class="token constant">O</span>’Reilly <span class="token keyword control-flow">for</span> just $299—a savings <span class="token keyword">of</span> $200<span class="token punctuation">.</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token property-access"><span class="token maybe-class-name">Get</span></span> <span class="token maybe-class-name">Deal</span> </span><span class="code-line"><span class="token maybe-class-name">Use</span> promo code <span class="token constant">SALESEPT22</span><span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">Expires</span></span> <span class="token number">9</span><span class="token operator">/</span><span class="token number">22</span><span class="token operator">/</span><span class="token number">22.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token maybe-class-name">This</span> offer is nontransferable and expires on <span class="token maybe-class-name">September</span> <span class="token number">22</span><span class="token punctuation">,</span> <span class="token number">2022</span><span class="token punctuation">,</span> at <span class="token number">11</span><span class="token operator">:</span>59pm <span class="token constant">PT</span><span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">This</span></span> offer is <span class="token keyword control-flow">for</span> individual memberships only<span class="token punctuation">.</span> <span class="token property-access function method"><span class="token maybe-class-name">Team</span></span> <span class="token punctuation">(</span>multiuser<span class="token punctuation">)</span> and enterprise accounts are not eligible<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">The</span></span> <span class="token constant">US</span> $299<span class="token operator">/</span>year offer is valid <span class="token keyword control-flow">for</span> the first year <span class="token keyword">of</span> your membership<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">Memberships</span></span> renew at the then<span class="token operator">-</span>current <span class="token function">price</span> <span class="token punctuation">(</span>currently <span class="token constant">US</span> $499<span class="token operator">/</span>year<span class="token punctuation">)</span> unless you cancel <span class="token keyword">in</span> accordance <span class="token keyword">with</span> our <span class="token maybe-class-name">Membership</span> <span class="token maybe-class-name">Agreement</span><span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">Tax</span></span> not included<span class="token punctuation">.</span> </span></code></pre></div><p>9-22 过后, 我收到的是这样的:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token maybe-class-name">We</span> talked to the lawyers and bought some more time to lock <span class="token keyword">in</span> your $299 <span class="token constant">O</span>’Reilly membership<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">But</span></span> soon it goes back up to $499<span class="token punctuation">.</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token property-access"><span class="token maybe-class-name">Get</span></span> <span class="token maybe-class-name">Deal</span> </span><span class="code-line"><span class="token maybe-class-name">Use</span> promo code <span class="token constant">SALESEPT22</span><span class="token punctuation">.</span> </span><span class="code-line"><span class="token property-access"><span class="token maybe-class-name">Expires</span></span> at midnight <span class="token constant">PT</span> <span class="token number">9</span><span class="token operator">/</span><span class="token number">27</span><span class="token operator">/</span><span class="token number">22.</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token maybe-class-name">This</span> offer is nontransferable and expires on <span class="token maybe-class-name">September</span> <span class="token number">27</span><span class="token punctuation">,</span> <span class="token number">2022</span><span class="token punctuation">,</span> at <span class="token number">11</span><span class="token operator">:</span>59pm <span class="token constant">PT</span><span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">This</span></span> offer is <span class="token keyword control-flow">for</span> individual memberships only<span class="token punctuation">.</span> <span class="token property-access function method"><span class="token maybe-class-name">Team</span></span> <span class="token punctuation">(</span>multiuser<span class="token punctuation">)</span> and enterprise accounts are not eligible<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">The</span></span> <span class="token constant">US</span> $299<span class="token operator">/</span>year offer is valid <span class="token keyword control-flow">for</span> the first year <span class="token keyword">of</span> your membership<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">Memberships</span></span> renew at the then<span class="token operator">-</span>current <span class="token function">price</span> <span class="token punctuation">(</span>currently <span class="token constant">US</span> $499<span class="token operator">/</span>year<span class="token punctuation">)</span> unless you cancel <span class="token keyword">in</span> accordance <span class="token keyword">with</span> our <span class="token maybe-class-name">Membership</span> <span class="token maybe-class-name">Agreement</span><span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">Tax</span></span> not included<span class="token punctuation">.</span> </span></code></pre></div><p>说好了过了 9-22 就没有这优惠了呢? 套路</p><p>另外就是, 其实在 9-22 之前我就已经买了这个, 所以, 另一方面, 其实 O&#x27;Reilly 的运营推送, 并不会考虑用户是否已经购买会员.</p> Sat, 24 Sep 2022 18:53:47 GMT ttyS3 https://ttys3.dev/blog/new-toml-crate new TOML crate https://ttys3.dev/blog/new-toml-crate <p>今天检查邮箱发现 <a href="https://github.com/toml-rs/toml-rs/issues/392">https://github.com/toml-rs/toml-rs/issues/392</a> 这个 issue 有更新.</p><p>由于 <code>toml</code> 这个 crate 完成的时候, TOML 标准本身还没有达到 1.0.0 稳定版, 因此这个 crate 实际上只实现了 TOML 标准 0.5 版本的功能.</p><p>但是现在 TOML 标准已经到了 <a href="https://toml.io/en/v1.0.0">1.0.0 版本</a>, 而 <code>toml</code> 这个 crate 的维护者却一直没有更新. 由于有了这个 issue, 讨论何时更新到1.0版本.</p><p>这是一个 2020 年的 issue. 一直没啥动静, 值得高兴的时候, 昨天终于有变动了:</p><p><a href="https://github.com/toml-rs/toml-rs/issues/392#issuecomment-1256456721">https://github.com/toml-rs/toml-rs/issues/392#issuecomment-1256456721</a></p><blockquote><p>Maintenance of this crate has moved to the <a href="https://github.com/toml-rs/toml">toml-rs/toml</a> repo. As a heads up, we plan to move <code>toml</code> to be on top of <code>toml_edit</code>, see <a href="https://github.com/toml-rs/toml/issues/340">toml-rs/toml#340</a>.</p><p>Closing this out. If this is still a problem, feel free to recreate this issue in the new repo.</p></blockquote><p>现在, 如果你打开 <a href="https://github.com/toml-rs/toml-rs">https://github.com/toml-rs/toml-rs</a>, 会发现 readme 已经变成了:</p><blockquote><p>Development of the <code>toml</code> crate has moved to <a href="https://github.com/toml-rs/toml/tree/master/crates/toml">https://github.com/toml-rs/toml/tree/master/crates/toml</a>.</p><p>This repo is now archived.</p></blockquote><p>其实还有一个 toml-rs/toml-rs 的作者为这个项目寻找新的维护者的issue, <a href="https://github.com/toml-rs/toml-rs/issues/460">https://github.com/toml-rs/toml-rs/issues/460</a></p><blockquote><p>I personally no longer have the time or energy to maintain this crate. I believe this is still pretty widely used as the default TOML implementation for Rust, however, so it&#x27;d be good to keep this maintained. I&#x27;m opening this to see if there is another who is willing to take over ownership and maintenance of this crate. In the meantime I will not be maintaining this crate other than if a security issue arises.</p></blockquote><p>今年6月左右 <a href="https://github.com/toml-rs/toml-rs/issues/460#issuecomment-1163202480">https://github.com/toml-rs/toml-rs/issues/460#issuecomment-1163202480</a>:</p><p>epage 写道:</p><blockquote><p>@alexcrichton what if we moved toml_edit::easy into toml?</p><p>A task I&#x27;ve been meaning to get to is to restructure toml_edit so a subset can more easily show up in public APIs, like cargo_metadata including toml. One possible route for that is to split toml_edit::easy out into its own crate and not expose any toml_edit types.</p><p>The downside being that toml_edit::easy has a ceiling on how fast it can get due to the format-preserving core its built on, even if the performance right now is roughly on par with toml.</p></blockquote><p>toml_edit 又是啥呢? 它现在已经被 cargo 使用了: <a href="https://github.com/rust-lang/cargo/pull/10086">https://github.com/rust-lang/cargo/pull/10086</a></p><p>根据这个 PR 的描述, 它是 A TOML 1.0 compliant parser</p><p>有个小问题就是, alexcrichton 将 toml-rs 的仓库转移到了 epage 的 toml-rs github 组织下面后(仓库从 alexcrichton/toml-rs 变成了 toml-rs/toml-rs ),</p><p>epage 关闭了旧仓库 (toml-rs/toml-rs) 的所有 issue, 并且这些 issue 似乎没有被转移到新的 repo (toml-rs/toml) 下面. 有一些用户对此感到不满, 主要在 <a href="https://github.com/toml-rs/toml/issues/340">https://github.com/toml-rs/toml/issues/340</a> 里面, 被隐藏的一评论.</p><p>不管怎么说, <code>toml</code> 这个 crate 重新重新有人维护了. 要感谢 alexcrichton, 它不但允许 epage 接管后, 继续使用 toml 这个 crate 名字, 而且将原来的 toml-rs 仓库也转移给了他.</p><p>所以, 新的 <code>toml</code> 库能继续使用 <code>toml</code> crate 这个名字, 并且旧使用也可以继续升级.</p><p>根据 <a href="https://crates.io/crates/toml">https://crates.io/crates/toml</a> 这个 crate 每天的下载量大概在 10万左右.</p><p>toml_edit 使用的 parser 是 <a href="https://docs.rs/combine">https://docs.rs/combine</a>, 其实它早期使用的是 nom, 至于为什么迁移到了 combine, 见这个issue : <a href="https://github.com/toml-rs/toml/issues/16">https://github.com/toml-rs/toml/issues/16</a></p><blockquote><p>nom is great for parsing binary formats, but no-so-great for parsing languages and reporting human readable errors. I&#x27;m considering combine, pest (procedural branch), peg, larlpop at the moment.</p></blockquote><p>目前 toml_edit 有个问题还没解决就是编译很慢: toml_edit is pretty slow to compile <a href="https://github.com/toml-rs/toml/issues/327">https://github.com/toml-rs/toml/issues/327</a></p><p>对比 <a href="https://github.com/rosetta-rs/parse-rosetta-rs">https://github.com/rosetta-rs/parse-rosetta-rs</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p>combine vs nom 对比: <a href="https://github.com/Marwes/combine/issues/73">https://github.com/Marwes/combine/issues/73</a></p><p>parser benchmark: <a href="https://github.com/rosetta-rs/parse-rosetta-rs">https://github.com/rosetta-rs/parse-rosetta-rs</a></p><p>Migrate toml to be on toml_edit <a href="https://github.com/toml-rs/toml/issues/340">https://github.com/toml-rs/toml/issues/340</a></p> Sat, 24 Sep 2022 18:01:49 GMT ttyS3 https://ttys3.dev/blog/linux-console-hidpi-font-config Linux Console HiDPI Font Config https://ttys3.dev/blog/linux-console-hidpi-font-config <p>老灯用的是 Nvidia 显卡闭源驱动. 显示器是 4K 的.</p><p>这操作基本上是每次装机后必备的, 这里记录下.</p><h2 id="linux-console-字体太大了"><a href="#linux-console-字体太大了" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Linux Console 字体太大了</h2><p>默认情况下有个问题就是: console 下面的字体太大了. 字体太大了, 是因为 frame buffer 分辨率太低了, 最简单的做法就是把 console 字体调小一点.</p><p>纯 console 下的字体是点阵字体. 默认的字体有点丑, 装个 terminus 吧:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">paru <span class="token parameter variable">-S</span> terminus-font </span></code></pre></div><p>切到 console 看下效果:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">setfont ter-d14b </span></code></pre></div><p>我这里设置 14 号是因为默认的太大了, 14相对较小一些. 另外 12 的话点太明显了, 不够清晰. 而14以上的又太大了. <code>b</code> 是 bold, <code>n</code> 后缀的则是 normal. bold 的会显得清晰一些. normal 的话还是容易看到点阵, 感觉回到古代了.</p><p>OK 的话就把配置持久化:</p><p>编辑 <code>/etc/vconsole.conf</code> 添加:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">FONT</span><span class="token operator">=</span>ter<span class="token operator">-</span>d14b </span></code></pre></div><h2 id="grub-hidpi-字体调整"><a href="#grub-hidpi-字体调整" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>GRUB HiDPI 字体调整</h2><p>参考 <a href="https://wiki.archlinux.org/title/HiDPI#GRUB">https://wiki.archlinux.org/title/HiDPI#GRUB</a></p><p>和 <a href="https://wiki.archlinux.org/title/GRUB/Tips_and_tricks#Setting_the_framebuffer_resolution">https://wiki.archlinux.org/title/GRUB/Tips_and_tricks#Setting_the_framebuffer_resolution</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://wiki.archlinux.org/title/Linux_console#Framebuffer_console">https://wiki.archlinux.org/title/Linux_console#Framebuffer_console</a></p> Wed, 24 Aug 2022 18:03:27 GMT ttyS3 linuxconsolevconsolefont https://ttys3.dev/blog/switch-from-gdm-to-lightdm-due-to-wayland-session-issue Switch From GDM to LightDM Due to GDM Wayland Session Issue https://ttys3.dev/blog/switch-from-gdm-to-lightdm-due-to-wayland-session-issue <p>工作电脑是双屏, 自动切换到 Wayland 之后, GDM 就没消停过.</p><p>经常性的从锁屏界面切回来后 GNOME 桌面会话退出了, 然后登录进去所有用户进程都结束了, 就跟重启后首次登录一样.</p><p>看 gdm 的日志也没看出啥. 家里的电脑同样是 Arch, 并且同样是 Nvidia 显卡, 唯一的不同时, 家里的是一个屏. 但是基本上家里的电脑就很少有放一段时间后再登录桌面会话消失的情况.</p><p>今天无意中在这 <a href="https://ask.fedoraproject.org/t/external-monitor-with-wayland-and-two-gpus-notebok/20387/3">https://ask.fedoraproject.org/t/external-monitor-with-wayland-and-two-gpus-notebok/20387/3</a> 看到一个解决方案: &quot;I read from other forum that the problem actually are with <code>GDM</code> (Gnome login screen). You could try to switch to <code>lightdm</code>.&quot;</p><p>所以, 是 GDM 的 bug, 换一个 DM 就好了. LightDM 虽然有点丑和简陋, 不过好歹解决了基本的使用问题.</p><p>丑点就丑点吧, 又不是不能用. GDM 再漂亮, 解决不了实际问题.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">paru <span class="token parameter variable">-S</span> lightdm lightdm-gtk-greeter </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> systemctl disable gdm </span><span class="code-line"><span class="token function">sudo</span> systemctl mask gdm </span><span class="code-line"><span class="token function">sudo</span> systemctl <span class="token class-name builtin">enable</span> lightdm </span></code></pre></div><p>测试了一天, 基本上确定 LightDM 解决了使用 GDM 时 Wayland session 经常被搞丢的问题.</p><h2 id="锁屏问题"><a href="#锁屏问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>锁屏问题</h2><p><code>dm-tool switch-to-greeter</code> 或 <code>dm-tool lock</code> 区别是, switch-to-greeter 会锁定然后回到登录界面, lock 会锁定并关闭显示器.</p><p>去 Keyboard -&gt; Custom Shortcuts 自己加个锁屏快捷键即可.</p><h2 id="hidpi-问题"><a href="#hidpi-问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>HiDPI 问题</h2><p>编辑 <code>/etc/lightdm/lightdm-gtk-greeter.conf</code></p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token punctuation">[</span>greeter<span class="token punctuation">]</span> </span><span class="code-line">xft<span class="token operator">-</span>dpi<span class="token operator">=</span><span class="token number">192</span> </span></code></pre></div><h2 id="sddm-折腾以失败告终-最终退回-lightdm"><a href="#sddm-折腾以失败告终-最终退回-lightdm" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>SDDM: 折腾以失败告终, 最终退回 LightDM</h2><p>SDDM 这个东西最近几个月基本上都没人提交代码, 并且对于 Wayland 的支持并不太好. 要用开发分支才有 Wayland 支持.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 安装 archlinuxcn/sddm-git 0.19.0.141.ge67307e-1</span> </span><span class="code-line"><span class="token comment"># e67307e 是 https://github.com/sddm/sddm/commits/develop 的最新提交.</span> </span><span class="code-line">paru <span class="token parameter variable">-S</span> sddm-git </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 安装点主题啥的</span> </span><span class="code-line">paru <span class="token parameter variable">-S</span> sddm-sugar-dark sddm-nordic-theme-git archlinux-themes-sddm </span></code></pre></div><blockquote><p>The default configuration file for SDDM can be found at <code>/usr/lib/sddm/sddm.conf.d/default.conf</code>. For any changes, create configuration file(s) in <code>/etc/sddm.conf.d/</code>. See sddm.conf(5) for all options.</p></blockquote><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">mkdir</span> /etc/sddm.conf.d/ </span></code></pre></div><p>预览主题效果:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">sddm-greeter --test-mode <span class="token parameter variable">--theme</span> /usr/share/sddm/themes/archlinux-soft-grey </span><span class="code-line"> </span><span class="code-line">sddm-greeter --test-mode <span class="token parameter variable">--theme</span> /usr/share/sddm/themes/elarun </span><span class="code-line"> </span><span class="code-line">sddm-greeter --test-mode <span class="token parameter variable">--theme</span> /usr/share/sddm/themes/maldives </span><span class="code-line"> </span><span class="code-line">sddm-greeter --test-mode <span class="token parameter variable">--theme</span> /usr/share/sddm/themes/maya </span></code></pre></div><p>然后就是按 <a href="https://wiki.archlinux.org/title/SDDM">https://wiki.archlinux.org/title/SDDM</a> 配置了.</p><p>最终没能到达显示登录界面:</p><blockquote><p>Auth: sddm-helper exited with 3 Greeter stopped. SDDM::Auth::HELPER_OTHER_ERROR</p></blockquote><p>去 Github issue 看了下, 好像蛮多 Wayland 遇到这个问题的.</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Initializing</span><span class="token operator spread">...</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Starting</span><span class="token operator spread">...</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Logind</span> <span class="token keyword">interface</span> <span class="token class-name">found</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Adding</span> <span class="token keyword">new</span> <span class="token class-name">display<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span></span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Loading</span> theme configuration <span class="token keyword module">from</span> <span class="token string">&quot;&quot;</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Using</span> <span class="token constant">VT</span> <span class="token number">3</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Display</span> server started<span class="token punctuation">.</span> </span><span class="code-line"><span class="token property-access">sddm</span><span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Socket</span> server starting<span class="token operator spread">...</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Socket</span> server started<span class="token punctuation">.</span> </span><span class="code-line"><span class="token property-access">sddm</span><span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Loading</span> theme configuration <span class="token keyword module">from</span> <span class="token string">&quot;/usr/share/sddm/themes/maldives/theme.conf&quot;</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Greeter</span> starting<span class="token operator spread">...</span> </span><span class="code-line">sddm<span class="token operator">-</span>helper<span class="token punctuation">[</span><span class="token number">45449</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">PAM</span><span class="token punctuation">]</span> <span class="token maybe-class-name">Starting</span><span class="token operator spread">...</span> </span><span class="code-line">sddm<span class="token operator">-</span>helper<span class="token punctuation">[</span><span class="token number">45449</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">PAM</span><span class="token punctuation">]</span> <span class="token maybe-class-name">Authenticating</span><span class="token operator spread">...</span> </span><span class="code-line">sddm<span class="token operator">-</span>helper<span class="token punctuation">[</span><span class="token number">45449</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token function">pam_unix</span><span class="token punctuation">(</span>sddm<span class="token operator">-</span>greeter<span class="token operator">:</span>session<span class="token punctuation">)</span><span class="token operator">:</span> session opened <span class="token keyword control-flow">for</span> user <span class="token function">sddm</span><span class="token punctuation">(</span>uid<span class="token operator">=</span><span class="token number">950</span><span class="token punctuation">)</span> by <span class="token function">root</span><span class="token punctuation">(</span>uid<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span> </span><span class="code-line">sddm<span class="token operator">-</span>helper<span class="token punctuation">[</span><span class="token number">45449</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">PAM</span><span class="token punctuation">]</span> returning<span class="token punctuation">.</span> </span><span class="code-line"><span class="token property-access">sddm</span><span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Greeter</span> session started successfully </span><span class="code-line">sddm<span class="token operator">-</span>helper<span class="token punctuation">[</span><span class="token number">45449</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">PAM</span><span class="token punctuation">]</span> <span class="token maybe-class-name">Closing</span> session </span><span class="code-line">sddm<span class="token operator">-</span>helper<span class="token punctuation">[</span><span class="token number">45449</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token function">pam_unix</span><span class="token punctuation">(</span>sddm<span class="token operator">-</span>greeter<span class="token operator">:</span>session<span class="token punctuation">)</span><span class="token operator">:</span> session closed <span class="token keyword control-flow">for</span> user sddm </span><span class="code-line">sddm<span class="token operator">-</span>helper<span class="token punctuation">[</span><span class="token number">45449</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">PAM</span><span class="token punctuation">]</span> <span class="token maybe-class-name">Ended</span><span class="token punctuation">.</span> </span><span class="code-line"><span class="token property-access">sddm</span><span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Auth</span><span class="token operator">:</span> sddm<span class="token operator">-</span>helper exited <span class="token keyword">with</span> <span class="token number">3</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Greeter</span> stopped<span class="token punctuation">.</span> <span class="token constant">SDDM</span><span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">Auth</span><span class="token operator">:</span><span class="token operator">:</span><span class="token constant">HELPER_OTHER_ERROR</span> </span><span class="code-line">sddm<span class="token punctuation">[</span><span class="token number">45447</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token maybe-class-name">Signal</span> received<span class="token operator">:</span> <span class="token constant">SIGTERM</span> </span></code></pre></div><p>有没有可能是 theme 的问题? 没去试了.</p><p>但我猜测, 可能是 Wayland Compositor 的问题. SDDM 自身也同样是运行在 Wayland 下的, 当桌面登录还没启动的时候, SDDM 需要一个 Wayland Compositor 来启动它的 greeter. 我用的是它默认的 weston, 我不是 KDE, 并没有 kwin.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://wiki.archlinux.org/title/LightDM">https://wiki.archlinux.org/title/LightDM</a></p><p><a href="https://wiki.archlinux.org/title/Display_manager#Graphical">https://wiki.archlinux.org/title/Display_manager#Graphical</a></p><p><a href="https://wiki.archlinux.org/title/SDDM">https://wiki.archlinux.org/title/SDDM</a></p><p><a href="https://github.com/sddm/sddm/issues/1537">https://github.com/sddm/sddm/issues/1537</a></p> Wed, 24 Aug 2022 17:38:04 GMT ttyS3 gdmlightdmwaylandnvidia https://ttys3.dev/blog/add-plantuml-support-to-hugo 给 Hugo 博客添加 PlantUML 支持 https://ttys3.dev/blog/add-plantuml-support-to-hugo <p>PlantUML 是最近才了解到的, 实际上这个东西存在已经很多年了.</p><p>之前有用过 mermaid, 但是 mermaid 的 flowchart 写起来很蛋疼.</p><p>PlantUML 的 activity diagram 对多行文本和 note 支持更好, 同时不用写太多的箭头和 A, B, C 这种标记.</p><p>mermaid 要支持多行文本, 当前只能用 <code>foo1&lt;br/&gt;foo2&lt;br/&gt;foo3</code> 的方式.</p><p>另一方面, A, B, C 这种标记, 当你突然想在中间插入一个的时候, 就会很蛋疼.</p><h2 id="添加到-hugo-模板"><a href="#添加到-hugo-模板" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>添加到 Hugo 模板</h2><p>这里我并没有采用 Front Matter 参数的方式来确定是否加载 plantuml-encoder js 文件, 因此老灯觉得这样太麻烦.</p><p>因此是通过判断内容是否包含 plantuml 代码块来实现动态加载.</p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line"> </span><span class="code-line"> <span class="token keyword">const</span> <span class="token function function-variable">loadScript</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">url<span class="token punctuation">,</span> onloadFunction</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">var</span> newScript <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">createElement</span><span class="token punctuation">(</span><span class="token string">&quot;script&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> newScript<span class="token punctuation">.</span><span class="token property-access function method function-variable method-variable">onerror</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">oError</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">throw</span> <span class="token keyword">new</span> <span class="token class-name">URIError</span><span class="token punctuation">(</span><span class="token string">&quot;The script &quot;</span> <span class="token operator">+</span> oError<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">src</span> <span class="token operator">+</span> <span class="token string">&quot; didn&#x27;t load correctly.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>onloadFunction<span class="token punctuation">)</span> <span class="token punctuation">{</span> newScript<span class="token punctuation">.</span><span class="token property-access">onload</span> <span class="token operator">=</span> onloadFunction<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">head</span><span class="token punctuation">.</span><span class="token property-access function method">insertAdjacentElement</span><span class="token punctuation">(</span><span class="token string">&#x27;beforeend&#x27;</span><span class="token punctuation">,</span> newScript<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> newScript<span class="token punctuation">.</span><span class="token property-access">src</span> <span class="token operator">=</span> url<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">const</span> <span class="token function function-variable">loadPlantUMLOnNeed</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> plantumlPrefix <span class="token operator">=</span> <span class="token string">&quot;language-plantuml&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">&quot;[class^=&quot;</span> <span class="token operator">+</span> plantumlPrefix <span class="token operator">+</span> <span class="token string">&quot;]&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">loadScript</span><span class="token punctuation">(</span><span class="token string">&#x27;https://cdn.jsdelivr.net/gh/jmnote/[email protected]/dist/plantuml-encoder.min.js&#x27;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name">Array</span><span class="token punctuation">.</span><span class="token property-access">prototype</span><span class="token punctuation">.</span><span class="token property-access function method">forEach</span><span class="token punctuation">.</span><span class="token property-access function method">call</span><span class="token punctuation">(</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">&quot;[class^=&quot;</span> <span class="token operator">+</span> plantumlPrefix <span class="token operator">+</span> <span class="token string">&quot;]&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">code</span><span class="token punctuation">)</span><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> image <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">createElement</span><span class="token punctuation">(</span><span class="token string">&quot;IMG&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> image<span class="token punctuation">.</span><span class="token property-access">loading</span> <span class="token operator">=</span> <span class="token string">&#x27;lazy&#x27;</span><span class="token punctuation">;</span> <span class="token comment">// Lazy loading</span> </span><span class="code-line"> image<span class="token punctuation">.</span><span class="token property-access">src</span> <span class="token operator">=</span> <span class="token string">&#x27;http://www.plantuml.com/plantuml/svg/~1&#x27;</span> <span class="token operator">+</span> plantumlEncoder<span class="token punctuation">.</span><span class="token property-access function method">encode</span><span class="token punctuation">(</span>code<span class="token punctuation">.</span><span class="token property-access">innerText</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> code<span class="token punctuation">.</span><span class="token property-access">parentNode</span><span class="token punctuation">.</span><span class="token property-access function method">insertBefore</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> code<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> code<span class="token punctuation">.</span><span class="token property-access">style</span><span class="token punctuation">.</span><span class="token property-access">display</span> <span class="token operator">=</span> <span class="token string">&#x27;none&#x27;</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token class-name console">console</span><span class="token punctuation">.</span><span class="token property-access function method">log</span><span class="token punctuation">(</span><span class="token string">&quot;PlantUML init done&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access function method">addEventListener</span><span class="token punctuation">(</span><span class="token string">&#x27;load&#x27;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// load PlantUML</span> </span><span class="code-line"> <span class="token function">loadPlantUMLOnNeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span></code></pre></div><h2 id="流程图"><a href="#流程图" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>流程图</h2><p>注: activity diagram 实际上和 flowchart 不是一个东西. 但是用 activity diagram 完全可以表现 flowchart 所要表现的东西. 实际上 activity diagram 比 传统意义上的 flowchart 更强大.</p><blockquote><p>Activity diagrams can be regarded as a form of a structured flowchart combined with a traditional data flow diagram. Typical flowchart techniques lack constructs for expressing concurrency.[5] However, the join and split symbols in activity diagrams only resolve this for simple cases; the meaning of the model is not clear when they are arbitrarily combined with decisions or loops. (活动图可以视为是种结构化的流程图,并且结合了传统的数据流程图。典型的流程图技术中缺乏表示并发性。不过,活动中的分离和汇合符号只解决了在简单情形下的应用,若是配合决策或是循环,其意义较不清楚) <a href="https://en.wikipedia.org/wiki/Activity_diagram">https://en.wikipedia.org/wiki/Activity_diagram</a></p></blockquote><p>以 mermaid 默认的 <a href="https://mermaid.live/edit#pako:eNpVkMtqw0AMRX9FaJVC_ANeFBo7ySbQQrPzeCE8cmZo5sFYpgTb_95x00KileCcexGasAuascRLomjgXCsPed6ayiQ7iKOhhaJ4nY8s4ILn2wy7zTHAYEKM1l9e7v5ulaCaTqvGIMb6r-WOqt_8u-cZ6uZEUUJsH8n5O8ywb-yHyfXPxCTOqUPTU9lT0VGCilKLW3ScHFmdz57WgEIx7FhhmVfNPY1XUaj8ktUxahLeayshYa65DrxFGiV83nyHpaSR_6XaUv6C-7OWH4tPW9M">flowchart example</a> 为例, 其代码如下:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">graph <span class="token constant">TD</span> </span><span class="code-line"> <span class="token constant">A</span><span class="token punctuation">[</span><span class="token maybe-class-name">Christmas</span><span class="token punctuation">]</span> <span class="token operator">--</span><span class="token operator">&gt;</span><span class="token operator">|</span><span class="token maybe-class-name">Get</span> money<span class="token operator">|</span> <span class="token constant">B</span><span class="token punctuation">(</span><span class="token maybe-class-name">Go</span> shopping<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token constant">B</span> <span class="token operator">--</span><span class="token operator">&gt;</span> <span class="token constant">C</span><span class="token punctuation">{</span><span class="token maybe-class-name">Let</span> me think<span class="token punctuation">}</span> </span><span class="code-line"> <span class="token constant">C</span> <span class="token operator">--</span><span class="token operator">&gt;</span><span class="token operator">|</span><span class="token maybe-class-name">One</span><span class="token operator">|</span> <span class="token constant">D</span><span class="token punctuation">[</span><span class="token maybe-class-name">Laptop</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token constant">C</span> <span class="token operator">--</span><span class="token operator">&gt;</span><span class="token operator">|</span><span class="token maybe-class-name">Two</span><span class="token operator">|</span> <span class="token constant">E</span><span class="token punctuation">[</span>iPhone<span class="token punctuation">]</span> </span><span class="code-line"> <span class="token constant">C</span> <span class="token operator">--</span><span class="token operator">&gt;</span><span class="token operator">|</span><span class="token maybe-class-name">Three</span><span class="token operator">|</span> <span class="token constant">F</span><span class="token punctuation">[</span>fa<span class="token operator">:</span>fa<span class="token operator">-</span>car <span class="token maybe-class-name">Car</span><span class="token punctuation">]</span> </span></code></pre></div><p>效果如下:</p><div><img alt="" src="https://ttys3.dev/static/assets/mermaid-flowchart-demo-2022-08-22_04-36-TOOT7BI3.png" width="1813" height="1621"/></div><p>而 PlantUML 写起来就更简单了.</p><p>用 UML 的<a href="https://plantuml.com/activity-diagram-beta">活动图</a>表示:</p><div class="relative"><pre><code class="code-highlight language-uml"><span class="code-line">@startuml </span><span class="code-line">: Christmas; </span><span class="code-line">-&gt; Get money; </span><span class="code-line">: Go shopping; </span><span class="code-line">switch (Let me think) </span><span class="code-line"> case (One) </span><span class="code-line"> : Laptop; </span><span class="code-line"> detach </span><span class="code-line"> case (Two) </span><span class="code-line"> : iPhone; </span><span class="code-line"> detach </span><span class="code-line"> case (Three) </span><span class="code-line"> : Car; </span><span class="code-line"> detach </span><span class="code-line">@enduml </span></code></pre></div><p>注意, PlantUML 默认是连接的, 这里为了实现上面 mermaid 一样的图样效果, 特意加上了额外的 <code>detach</code> (一般情况下都不需要手动加 detach), 同时也没有写 <code>start</code> 和 <code>stop</code>标记.</p><img src="https://www.plantuml.com/plantuml/svg/TSnD2i8m48RXVKxnBUl22oGWXIwwAUZ22mpfu0IR7v8fnTkBYg8Bboyyl7rJghh6nLWCKaFJICsP_G4ZAs9EV7F6Oineaai9wU9Csu9wGJSz14CbfElE082dnkYEYLzfCL7HNDopPbRoykNEMtwxS9AS-9-Jof_ZGFM7zPpcDIvt"/><h2 id="时序图"><a href="#时序图" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>时序图</h2><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">sequenceDiagram </span><span class="code-line"> <span class="token maybe-class-name">Alice</span><span class="token operator">-</span><span class="token operator">&gt;&gt;</span><span class="token operator">+</span><span class="token maybe-class-name">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Hello</span> <span class="token maybe-class-name">John</span><span class="token punctuation">,</span> how are you<span class="token operator">?</span> </span><span class="code-line"> <span class="token maybe-class-name">Alice</span><span class="token operator">-</span><span class="token operator">&gt;&gt;</span><span class="token operator">+</span><span class="token maybe-class-name">John</span><span class="token operator">:</span> <span class="token maybe-class-name">John</span><span class="token punctuation">,</span> can you hear me<span class="token operator">?</span> </span><span class="code-line"> <span class="token maybe-class-name">John</span><span class="token operator">--</span><span class="token operator">&gt;&gt;</span><span class="token operator">-</span><span class="token maybe-class-name">Alice</span><span class="token operator">:</span> <span class="token maybe-class-name">Hi</span> <span class="token maybe-class-name">Alice</span><span class="token punctuation">,</span> <span class="token constant">I</span> can hear you<span class="token operator">!</span> </span><span class="code-line"> <span class="token maybe-class-name">John</span><span class="token operator">--</span><span class="token operator">&gt;&gt;</span><span class="token operator">-</span><span class="token maybe-class-name">Alice</span><span class="token operator">:</span> <span class="token constant">I</span> feel great<span class="token operator">!</span> </span></code></pre></div><div><img alt="" src="https://ttys3.dev/static/assets/mermaid-sequence-diagram-demo-2022-08-22_04-48-SMNQD3LD.png" width="2103" height="1415"/></div><p>用 PlantUML 可以完全复现如下:</p><div class="relative"><pre><code class="code-highlight language-uml"><span class="code-line">```plantuml </span><span class="code-line"> Alice -&gt; John: Hello John, how are you? </span><span class="code-line"> activate John </span><span class="code-line"> </span><span class="code-line"> Alice -&gt; John: John, can you hear me? </span><span class="code-line"> activate John </span><span class="code-line"> John--&gt; Alice: Hi Alice, I can hear you! </span><span class="code-line"> deactivate John </span><span class="code-line"> </span><span class="code-line"> John--&gt; Alice: I feel great! </span><span class="code-line"> deactivate John </span><span class="code-line">``` </span></code></pre></div><img src="https://www.plantuml.com/plantuml/svg/TOun2iCm34Ntdk9rZo-G8QLRqbi8LwaDRWp6QSdjI-GjD8luwEiz171FqIjku973qZDgIjboHyXVf2XRNcyN0F4rVgIgzRQnSL0qsCkoWmILmblF17jmRcYEdZ6sr36PmUWjhrSxVkh91mVBnAoQU1ML-fVy0G00"/><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://plantuml.com/activity-diagram-beta">https://plantuml.com/activity-diagram-beta</a></p><p><a href="https://plantuml.com/sequence-diagram">https://plantuml.com/sequence-diagram</a></p><p><a href="https://mogeko.me/posts/zh-cn/083/">https://mogeko.me/posts/zh-cn/083/</a></p> Sun, 21 Aug 2022 20:25:00 GMT ttyS3 mermaidhugoumlflowchartplantuml https://ttys3.dev/blog/hugo-vs-zola Hugo vs Zola https://ttys3.dev/blog/hugo-vs-zola <table><thead><tr><th>对比项</th><th>Hugo</th><th>Zola</th></tr></thead><tbody><tr><td>实现语言</td><td>Golang</td><td>Rust</td></tr><tr><td>主题数量</td><td>丰富</td><td>较少</td></tr><tr><td>模板引擎</td><td>Go Template</td><td>Tera</td></tr><tr><td>CSS 支持</td><td>SASS / SCSS, PostCSS</td><td>SASS / SCSS</td></tr><tr><td>Page Bundle 支持</td><td>Yes</td><td>Yes</td></tr><tr><td>Front Matter 支持</td><td>TOML/YAML/JSON/ORG</td><td>TOML/YAML</td></tr><tr><td>子目录支持</td><td>自动</td><td>需要手动给每个子目录添加 <code>_index.md</code></td></tr><tr><td>生成 URL 配置</td><td>支持</td><td>不支持</td></tr></tbody></table><blockquote><p>Zola uses the <code>Tera</code> template engine, which is very similar to <code>Jinja2</code>, Liquid and Twig.</p></blockquote><p>关于 Front Matter, 刚开始 Zola 是极力不想添加 YAML 支持的, 后面添加了, 但是并没有在文档里面说明 (作者极力不提倡使用).</p><p>事实上我觉得写 markdown 用 TOML Front Matter 才是反人类.</p><p>Hugo 通通 pipeline 可以支持很多东西: <a href="https://gohugo.io/hugo-pipes/">https://gohugo.io/hugo-pipes/</a></p><p>而 Zola 则局限于 SASS 的 Rust 绑定, 今天无法支持 PostCSS : <a href="https://zola.discourse.group/t/add-postcss-support/556">https://zola.discourse.group/t/add-postcss-support/556</a></p><p>子目录支持方面, Zola 也是很糟心.</p><p>需要给每个子目录添加 <code>_index.md</code> 文件, 否则不会索引到 pages.</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token operator">++</span><span class="token operator">+</span> </span><span class="code-line">paginate_by <span class="token operator">=</span> <span class="token number">4</span> </span><span class="code-line">sort_by <span class="token operator">=</span> <span class="token string">&quot;date&quot;</span> </span><span class="code-line">transparent <span class="token operator">=</span> <span class="token boolean">true</span> </span><span class="code-line"><span class="token operator">++</span><span class="token operator">+</span> </span></code></pre></div><p>注意这里的 <code>transparent = true</code> 一定要添加. 要不然你在模板里面无法看到子目录的内容. <code>paginate_by</code> 也一定要添加, 要不然不会有 <code>paginator</code></p><p>这是一种很奇怪的设定, Zola 和 Hugo 这方面是反的. Hugo 是默认支持子目录, Zola 则是默认不支持. 维护众多子目录下的 <code>_index.md</code> 文件是很糟糕的, 从这方面来说, Hugo 更实用.</p><p>Zola 的作者似乎比较武断, 表示无意支持 URL 生成规则: <a href="https://github.com/getzola/zola/issues/635">https://github.com/getzola/zola/issues/635</a></p><p>而 Hugo 则支持灵活地模板规则. 比如 配置为 <code>/post/:filename/</code> 则 <code>/posts/sub1/sub2/my-post-filename.md</code> 可以生成 <code>/post/my-post-filename/index.html</code></p><p>而 Zola 则只能按照目录结构生成 <code>/posts/sub1/sub2/my-post-filename.html</code></p><p>目前看来, Zola 也已经不再是新项目了, 但是作者对于一些东西的接纳程度, 仍然是制约其发展的主要因素. 社区的力量应该还是比较强大的, 但是作者的接纳程度, 可能是一个问题.</p><p>而 Hugo 可能在朝着另一个极端在发展, 不断地在添加新功能.</p><p>综合起来, 除非你对 Zola 有特别偏爱, 否则不要使用 Zola. 大部分情况下, Hugo 能很好的满足需求, 而 Zola 则不一定.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://jamstack.org/generators/">https://jamstack.org/generators/</a></p><p><a href="https://gohugo.io/content-management/front-matter/">https://gohugo.io/content-management/front-matter/</a></p><p><a href="https://www.getzola.org/documentation/templates/pagination/">https://www.getzola.org/documentation/templates/pagination/</a></p><p><a href="https://www.getzola.org/documentation/templates/overview/">https://www.getzola.org/documentation/templates/overview/</a></p><p><a href="https://www.getzola.org/themes/">https://www.getzola.org/themes/</a></p><p><a href="https://themes.gohugo.io/">https://themes.gohugo.io/</a></p> Sun, 21 Aug 2022 19:50:16 GMT ttyS3 zolahugo https://ttys3.dev/blog/fixup-epiphany-segmentation-fault-under-wayland Fixup Epiphany Segmentation Fault Under Wayland https://ttys3.dev/blog/fixup-epiphany-segmentation-fault-under-wayland <h2 id="缘由"><a href="#缘由" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h2><p>自从老灯切到了 Wayland, 好像 epiphany 就基本上打不开了. 由于这个浏览器平常也不怎么用, 因此也就一直没管. 今天周末, 刚好抽空简单看下.</p><h2 id="排查"><a href="#排查" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>排查</h2><p>先用 gdb 看看:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"> ❯ gdb epiphany </span><span class="code-line">GNU gdb <span class="token punctuation">(</span>GDB<span class="token punctuation">)</span> <span class="token number">12.1</span> </span><span class="code-line">This GDB supports auto-downloading debuginfo from the following URLs: </span><span class="code-line">https://debuginfod.archlinux.org </span><span class="code-line">Enable debuginfod <span class="token keyword">for</span> this session? <span class="token punctuation">(</span>y or <span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">)</span> y </span><span class="code-line">Debuginfod has been enabled. </span><span class="code-line">To <span class="token function">make</span> this setting permanent, <span class="token function">add</span> <span class="token string">&#x27;set debuginfod enabled on&#x27;</span> to .gdbinit. </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">(</span>gdb<span class="token punctuation">)</span> r </span><span class="code-line">Starting program: /usr/bin/epiphany </span><span class="code-line"><span class="token punctuation">[</span>Thread debugging using libthread_db enabled<span class="token punctuation">]</span> </span><span class="code-line">Using <span class="token function">host</span> libthread_db library <span class="token string">&quot;/usr/lib/libthread_db.so.1&quot;</span><span class="token builtin class-name">.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">..</span>. </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">Thread <span class="token number">1</span> <span class="token string">&quot;epiphany&quot;</span> received signal SIGSEGV, Segmentation fault. </span><span class="code-line">wl_resource_get_destroy_listener <span class="token punctuation">(</span>resource<span class="token operator">=</span>0x0, <span class="token variable assign-left">notify</span><span class="token operator">=</span>0x7ffff1003980 <span class="token operator">&lt;</span><span class="token punctuation">(</span>anonymous namespace<span class="token punctuation">)</span>::ClientBundleEGL::bufferDestroyListenerCallback<span class="token punctuation">(</span>wl_listener*, void*<span class="token punctuation">)</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> at <span class="token punctuation">..</span>/wayland-1.21.0/src/wayland-server.c:850 </span><span class="code-line"><span class="token number">850</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>resource_is_deprecated<span class="token punctuation">(</span>resource<span class="token punctuation">))</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">(</span>gdb<span class="token punctuation">)</span> bt </span><span class="code-line"><span class="token comment">#0 wl_resource_get_destroy_listener</span> </span><span class="code-line"> <span class="token punctuation">(</span>resource<span class="token operator">=</span>0x0, <span class="token variable assign-left">notify</span><span class="token operator">=</span>0x7ffff1003980 <span class="token operator">&lt;</span><span class="token punctuation">(</span>anonymous namespace<span class="token punctuation">)</span>::ClientBundleEGL::bufferDestroyListenerCallback<span class="token punctuation">(</span>wl_listener*, void*<span class="token punctuation">)</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> at <span class="token punctuation">..</span>/wayland-1.21.0/src/wayland-server.c:850 </span><span class="code-line"><span class="token comment">#1 0x00007ffff1005b4b in (anonymous namespace)::ClientBundleEGL::findImage (bufferResource=0x0, this=0x55555686c9c0)</span> </span><span class="code-line"> at <span class="token punctuation">..</span>/WPEBackend-fdo/src/view-backend-exportable-fdo-egl.cpp:270 </span><span class="code-line"><span class="token comment">#2 (anonymous namespace)::ClientBundleEGL::exportBuffer(wl_resource*) (this=0x55555686c9c0, bufferResource=0x0)</span> </span><span class="code-line"> at <span class="token punctuation">..</span>/WPEBackend-fdo/src/view-backend-exportable-fdo-egl.cpp:181 </span><span class="code-line"><span class="token comment">#3 0x00007ffff18cb536 in ffi_call_unix64 () at ../src/x86/unix64.S:105</span> </span><span class="code-line"><span class="token comment">#4 0x00007ffff18c8037 in ffi_call_int</span> </span><span class="code-line"> <span class="token punctuation">(</span>cif<span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, <span class="token variable assign-left">fn</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, <span class="token variable assign-left">rvalue</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, <span class="token variable assign-left">avalue</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, <span class="token variable assign-left">closure</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span><span class="token punctuation">)</span> </span><span class="code-line"> at <span class="token punctuation">..</span>/src/x86/ffi64.c:672 </span><span class="code-line"><span class="token comment">#5 0x00007ffff0403ada in wl_closure_invoke (closure=closure@entry=0x555556cd4880, target=&lt;optimized out&gt;, </span> </span><span class="code-line"> target@entry<span class="token operator">=</span>0x555556c7ba20, <span class="token variable assign-left">opcode</span><span class="token operator">=</span>opcode@entry<span class="token operator">=</span><span class="token number">6</span>, <span class="token variable assign-left">data</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, data@entry<span class="token operator">=</span>0x555556a18b40, <span class="token variable assign-left">flags</span><span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">)</span> </span><span class="code-line"> at <span class="token punctuation">..</span>/wayland-1.21.0/src/connection.c:1025 </span><span class="code-line"><span class="token comment">#6 0x00007ffff0408010 in wl_client_connection_data (fd=&lt;optimized out&gt;, mask=&lt;optimized out&gt;, data=&lt;optimized out&gt;)</span> </span><span class="code-line"> at <span class="token punctuation">..</span>/wayland-1.21.0/src/wayland-server.c:437 </span><span class="code-line"><span class="token comment">#7 0x00007ffff04069e2 in wl_event_loop_dispatch (loop=0x5555559b30a0, timeout=&lt;optimized out&gt;)</span> </span><span class="code-line"> at <span class="token punctuation">..</span>/wayland-1.21.0/src/event-loop.c:1027 </span><span class="code-line"><span class="token comment">#8 0x00007ffff10068c5 in operator() (__closure=0x0, base=0x555555a5f670) at ../WPEBackend-fdo/src/ws.cpp:77</span> </span><span class="code-line"><span class="token comment">#9 _FUN(GSource*, GSourceFunc, gpointer) () at ../WPEBackend-fdo/src/ws.cpp:86</span> </span><span class="code-line"><span class="token comment">#10 0x00007ffff734cc6b in g_main_dispatch (context=0x5555559210e0) at ../glib/glib/gmain.c:3417</span> </span><span class="code-line"><span class="token comment">#11 g_main_context_dispatch (context=0x5555559210e0) at ../glib/glib/gmain.c:4135</span> </span><span class="code-line"><span class="token comment">#12 0x00007ffff73a3001 in g_main_context_iterate.constprop.0</span> </span><span class="code-line"> <span class="token punctuation">(</span>context<span class="token operator">=</span>context@entry<span class="token operator">=</span>0x5555559210e0, <span class="token variable assign-left">block</span><span class="token operator">=</span>block@entry<span class="token operator">=</span><span class="token number">1</span>, <span class="token variable assign-left">dispatch</span><span class="token operator">=</span>dispatch@entry<span class="token operator">=</span><span class="token number">1</span>, <span class="token variable assign-left">self</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span><span class="token punctuation">)</span> </span><span class="code-line"> at <span class="token punctuation">..</span>/glib/glib/gmain.c:4211 </span><span class="code-line"><span class="token variable parameter">--Type</span> <span class="token operator">&lt;</span>RET<span class="token operator">&gt;</span> <span class="token keyword">for</span> more, q to quit, c to <span class="token builtin class-name">continue</span> without paging--c </span><span class="code-line"><span class="token comment">#13 0x00007ffff734a392 in g_main_context_iteration (context=context@entry=0x5555559210e0, may_block=may_block@entry=1) at ../glib/glib/gmain.c:4276</span> </span><span class="code-line"><span class="token comment">#14 0x00007ffff750730e in g_application_run (application=0x5555559601d0, argc=argc@entry=1, argv=argv@entry=0x7fffffffd3b8) at ../glib/gio/gapplication.c:2569</span> </span><span class="code-line"><span class="token comment">#15 0x0000555555558714 in main (argc=&lt;optimized out&gt;, argv=&lt;optimized out&gt;) at ../epiphany/src/ephy-main.c:428</span> </span><span class="code-line"><span class="token punctuation">(</span>gdb<span class="token punctuation">)</span> </span></code></pre></div><p>其实后台的调用栈基本上也没啥用. 简单的 segment fault 信息已经告诉我们原因了:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token maybe-class-name">Thread</span> <span class="token number">1</span> <span class="token string">&quot;epiphany&quot;</span> received signal <span class="token constant">SIGSEGV</span><span class="token punctuation">,</span> <span class="token maybe-class-name">Segmentation</span> fault<span class="token punctuation">.</span> </span><span class="code-line"><span class="token function property-access method">wl_resource_get_destroy_listener</span> <span class="token punctuation">(</span>resource<span class="token operator">=</span><span class="token number">0x0</span><span class="token punctuation">,</span> notify<span class="token operator">=</span><span class="token number">0x7ffff1003980</span> <span class="token operator">&lt;</span><span class="token punctuation">(</span>anonymous namespace<span class="token punctuation">)</span><span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">ClientBundleEGL</span><span class="token operator">:</span><span class="token operator">:</span><span class="token function">bufferDestroyListenerCallback</span><span class="token punctuation">(</span>wl_listener<span class="token operator">*</span><span class="token punctuation">,</span> <span class="token keyword">void</span><span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> at <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">/</span>wayland<span class="token operator">-</span><span class="token number">1.21</span><span class="token number">.0</span><span class="token operator">/</span>src<span class="token operator">/</span>wayland<span class="token operator">-</span>server<span class="token punctuation">.</span><span class="token property-access">c</span><span class="token operator">:</span><span class="token number">850</span> </span><span class="code-line"><span class="token number">850</span> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token function">resource_is_deprecated</span><span class="token punctuation">(</span>resource<span class="token punctuation">)</span><span class="token punctuation">)</span> </span></code></pre></div><p>调用<code>wl_resource_get_destroy_listener</code> 时传入的第一个 <code>resource</code> 参数是一个 null 指针, 导致 850 行的 <code>resource_is_deprecated(resource)</code> 调用 SIGSEGV 了</p><p>到这里你是不是觉得我要操刀开始去看代码了?</p><p>no. 首先,我打算把这个bt 信息给提交到 GNOME issue. 结果 Gitlab 的 issue 管理还是挺智能的. 当我敲出 &quot;Epiphany crash Under Wayland&quot; 时, 下面自动弹出了一些它觉得可能是同一个问题的issue, 于是我点进去了 <a href="https://gitlab.gnome.org/GNOME/epiphany/-/issues/1832">https://gitlab.gnome.org/GNOME/epiphany/-/issues/1832</a></p><p>这个 issue creator 比我多做了一步, 他还尝试X11方式启动, 发现完全正常. 我试一下, <code>GDK_BACKEND=x11 epiphany</code>, 结果也是完全正常的.</p><p>GNOME 那边的人回复了, Michael Catanzaro @mcatanzaro (严格上来说是在 Red Hat的人):</p><blockquote><p>Hi, you&#x27;ll need to report this on the <a href="https://github.com/Igalia/WPEBackend-fdo/issues">wpebackend-fdo</a> issue tracker, here. Good luck....</p></blockquote><p>随即issue马上被关闭了, 并加上了 <code>Not GNOME</code> label.</p><p>嗯, GNOME 的人关 issue 速度都挺快的.</p><p>上游的问题, 关了.</p><p>看上去是个悲伤的故事.</p><p>不过, 3分钟后, the guy 又回复了:</p><blockquote><p>Actually, looks like it is already fixed by <a href="https://github.com/Igalia/WPEBackend-fdo/pull/176/">https://github.com/Igalia/WPEBackend-fdo/pull/176/</a> which is awaiting review. (CC @aperezdc)</p></blockquote><p>这个修复主要就是像我们上面说的, 在调用 <code>wl_resource_get_destroy_listener</code> 之前, 判断第一个参数确保它不是 null 指针.</p><p>不过除了这个提交, 他还做了第二个提交:</p><blockquote><p>Only delete images in releaseImage Deleting images in bufferDestroyListenerCallback is incorrect, and caused a double free.</p></blockquote><p><a href="https://github.com/Igalia/WPEBackend-fdo/pull/176/commits/fcf330cc3036808b6fb83ee7a6cef4f5ff9e00c8">https://github.com/Igalia/WPEBackend-fdo/pull/176/commits/fcf330cc3036808b6fb83ee7a6cef4f5ff9e00c8</a></p><p>所以, 专业的东西,还是得专业的人去修, 如果是由我们自己动手, 可能只会有第一个commit, 也就是 null 判断.</p><h2 id="自己动手"><a href="#自己动手" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>自己动手</h2><p>等上游的上游修复, 上游再修复, package packer 再更新, 这个周期可能相当长. 好在 Arch 里面要自己编译一个带 patch 的东西是非常简单的事情. 这可能也是 Arch 最大的魔力之一吧.</p><p>下载官方的 <a href="https://github.com/archlinux/svntogit-packages/blob/packages/wpebackend-fdo/trunk/PKGBUILD">https://github.com/archlinux/svntogit-packages/blob/packages/wpebackend-fdo/trunk/PKGBUILD</a> 然后加一行 patch 命令即可.</p><p>至于 patch 文件, Github 的 PR 都是直接 URL 后面加上 <code>.patch</code>即可取: <a href="https://github.com/Igalia/WPEBackend-fdo/pull/176.patch">https://github.com/Igalia/WPEBackend-fdo/pull/176.patch</a></p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">From 3318283ffe62a536cfbff307c77505d848d7098f Mon Sep 17 00:00:00 2001 </span><span class="code-line">From: Jordy Vieira &lt;[email protected]&gt; </span><span class="code-line">Date: Sat, 9 Jul 2022 17:17:14 -0300 </span><span class="code-line">Subject: [PATCH 1/2] Fix SIGSEGV </span><span class="code-line"> </span><span class="code-line deleted"><span class="token coord">---</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">src/view-backend-exportable-fdo-egl.cpp | 8 +++++--- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">1 file changed, 5 insertions(+), 3 deletions(-) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line">diff --git a/src/view-backend-exportable-fdo-egl.cpp b/src/view-backend-exportable-fdo-egl.cpp </span><span class="code-line">index 09bb2bf..1a73269 100644 </span><span class="code-line deleted"><span class="token coord">--- a/src/view-backend-exportable-fdo-egl.cpp</span> </span><span class="code-line inserted"><span class="token coord">+++ b/src/view-backend-exportable-fdo-egl.cpp</span> </span><span class="code-line">@@ -267,9 +267,11 @@ class ClientBundleEGL final : public ClientBundle { </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">private: </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> struct wpe_fdo_egl_exported_image* findImage(struct wl_resource* bufferResource) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> { </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line"> if (auto* listener = wl_resource_get_destroy_listener(bufferResource, bufferDestroyListenerCallback)) { </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token deleted prefix">-</span><span class="token line"> struct wpe_fdo_egl_exported_image* image; </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token deleted prefix">-</span><span class="token line"> return wl_container_of(listener, image, bufferDestroyListener); </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> if (bufferResource) { </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line"> if (auto* listener = wl_resource_get_destroy_listener(bufferResource, bufferDestroyListenerCallback)) { </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line"> struct wpe_fdo_egl_exported_image* image; </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line"> return wl_container_of(listener, image, bufferDestroyListener); </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line"> } </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> } </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> return nullptr; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line">From fcf330cc3036808b6fb83ee7a6cef4f5ff9e00c8 Mon Sep 17 00:00:00 2001 </span><span class="code-line">From: Jordy Vieira &lt;[email protected]&gt; </span><span class="code-line">Date: Sat, 9 Jul 2022 19:16:03 -0300 </span><span class="code-line">Subject: [PATCH 2/2] Only delete images in releaseImage </span><span class="code-line"> </span><span class="code-line">Deleting images in bufferDestroyListenerCallback is incorrect, and </span><span class="code-line">caused a double free. </span><span class="code-line deleted"><span class="token coord">---</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">src/view-backend-exportable-fdo-egl.cpp | 5 ----- </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">1 file changed, 5 deletions(-) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line">diff --git a/src/view-backend-exportable-fdo-egl.cpp b/src/view-backend-exportable-fdo-egl.cpp </span><span class="code-line">index 1a73269..0031222 100644 </span><span class="code-line deleted"><span class="token coord">--- a/src/view-backend-exportable-fdo-egl.cpp</span> </span><span class="code-line inserted"><span class="token coord">+++ b/src/view-backend-exportable-fdo-egl.cpp</span> </span><span class="code-line">@@ -247,8 +247,6 @@ class ClientBundleEGL final : public ClientBundle { </span><span class="code-line"> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> void releaseImage(struct wpe_fdo_egl_exported_image* image) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> { </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line"> image-&gt;exported = false; </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token deleted prefix">-</span><span class="token line"> </span></span></span><span class="code-line"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> if (image-&gt;bufferResource) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> viewBackend-&gt;releaseBuffer(image-&gt;bufferResource); </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> else </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>@@ -297,9 +295,6 @@ class ClientBundleEGL final : public ClientBundle { </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> image = wl_container_of(listener, image, bufferDestroyListener); </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> image-&gt;bufferResource = nullptr; </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line"> </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token deleted prefix">-</span><span class="token line"> if (!image-&gt;exported) </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token deleted prefix">-</span><span class="token line"> deleteImage(image); </span></span></span><span class="code-line"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> } </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">}; </span></span></span></code></pre></div><p>打包好的文件老灯放这:</p><p><a href="https://github.com/ttys3/my-archlinux-pkgbuild/releases/tag/wpebackend-fdo-1.12.0-2">https://github.com/ttys3/my-archlinux-pkgbuild/releases/tag/wpebackend-fdo-1.12.0-2</a></p><p><code>paru -U ./wpebackend-fdo-1.12.0-2-x86_64.pkg.tar.zst</code> 安装即可.</p><p>测试下, 不再 crash 了.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://wiki.archlinux.org/title/Debuginfod">https://wiki.archlinux.org/title/Debuginfod</a></p><p><a href="https://github.com/archlinux/svntogit-packages/blob/packages/wpebackend-fdo/trunk/PKGBUILD">https://github.com/archlinux/svntogit-packages/blob/packages/wpebackend-fdo/trunk/PKGBUILD</a></p> Sat, 30 Jul 2022 12:07:38 GMT ttyS3 webkitgtkwebkitpatchwaylandepiphany https://ttys3.dev/blog/cobra-has-viper-deps-removed cobra 终于移除了 viper 依赖 https://ttys3.dev/blog/cobra-has-viper-deps-removed <p>cobra 可能是 Golang 里面最好用的 cli 命令行类库了. 没有之一.</p><p>其它也有一些功能类似的, 但是做到像 cobra 这样功能强大又简单易用的, 着实不多.</p><p>但是长期以来, cobra 依赖重量级的 viper module, 这两个东西都是同一个作者开发的, 因此其实也可以理解.</p><p>老灯最近突然发现, 随着社区力量的参与, cobra 的 viper 依赖居然在 1.4.0 版本被移除了!</p><p>老灯不是唯一一个不喜欢 viper 这种全家桶依赖类型的包的.</p><p>甚至有人 fork 出一份专门移除了 viper 依赖: <a href="https://github.com/muesli/coral">https://github.com/muesli/coral</a></p><p>这个作者专门在 readme 说明了缘由:</p><blockquote><p>I love <a href="https://github.com/spf13/cobra">Cobra</a> and I love <a href="https://github.com/spf13/viper">Viper</a>. They are great projects, incredibly useful and outstandingly important for the Go community. But sometimes, just sometimes, don&#x27;t you wish you could use Cobra without the entire dependency chain Viper drags in?</p><p>This is what <code>Coral</code> is: a Cobra fork without any of the Viper dependencies and features. This will hopefully be a soft fork with only the minimal changes required to decouple Viper from Cobra. The aim is to follow upstream Cobra development as closely as possible.</p></blockquote><p>事实上由于 viper 依赖了问题, 老灯已经取消了 cobra star, 最近也是从 coral 的 readme 看到的消息, 作者甚至还贴心地给出了迁移命令:</p><blockquote><p>Recent Cobra versions, v1.4.0 and onward, removed the dependency on Viper as well. You might switch back to Cobra using <code>gofmt</code>:</p></blockquote><div class="relative"><pre><code class="code-highlight language-sh"><span class="code-line">gofmt <span class="token parameter variable">-w</span> <span class="token parameter variable">-r</span> <span class="token string">&#x27;&quot;github.com/muesli/coral&quot; -&gt; &quot;github.com/spf13/cobra&quot;&#x27;</span> <span class="token builtin class-name">.</span> </span><span class="code-line">gofmt <span class="token parameter variable">-w</span> <span class="token parameter variable">-r</span> <span class="token string">&#x27;&quot;github.com/muesli/coral/doc&quot; -&gt; &quot;github.com/spf13/cobra/doc&quot;&#x27;</span> <span class="token builtin class-name">.</span> </span><span class="code-line">gofmt <span class="token parameter variable">-w</span> <span class="token parameter variable">-r</span> <span class="token string">&#x27;coral -&gt; cobra&#x27;</span> <span class="token builtin class-name">.</span> </span><span class="code-line"> </span><span class="code-line">go get <span class="token parameter variable">-u</span> github.com/spf13/cobra </span><span class="code-line">go mod tidy </span></code></pre></div><p>其实 cobra 的 viper 依赖主要是其 cli 工具引入的, 因此 1.4.0 版本将这个 cli 工具放到单独的包里了.</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">go <span class="token function">install</span> github.com/spf13/cobra-cli@latest </span></code></pre></div> Wed, 27 Jul 2022 15:15:35 GMT ttyS3 golangclicobraviper https://ttys3.dev/blog/serde-custom-serialization serde自定义序列化 https://ttys3.dev/blog/serde-custom-serialization <p>serde 几乎是目前 Rust 生态中最常用的序列化与反序列化库了.</p><h2 id="golang-实现"><a href="#golang-实现" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Golang 实现</h2><p>作为一个 Golang 程序员来说, 免不了要对比一下.</p><p>Golang 官方库直接实现了 json 的序列化和反序列化.</p><p>对于序列化和反序列化, Go 都是用一个简单的接口<code>interface</code>表示:</p><div class="relative"><pre><code class="code-highlight language-go"><span class="code-line"><span class="token comment">// https://pkg.go.dev/encoding/json#Marshaler</span> </span><span class="code-line"><span class="token keyword">type</span> Marshaler <span class="token keyword">interface</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">MarshalJSON</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">byte</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// https://pkg.go.dev/encoding/json#Unmarshaler</span> </span><span class="code-line"><span class="token keyword">type</span> Unmarshaler <span class="token keyword">interface</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">UnmarshalJSON</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">byte</span><span class="token punctuation">)</span> <span class="token builtin">error</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>注意这个接口只是针对 JSON 的, 接口名后缀<code>JSON</code> 是有意义的. 因为对于同一个数据类型, 它可能需要实现很多种格式的序列化, 比如 yaml, toml 等. 如果按这个命名来, 它可能是: <code>MarshalYaml</code>, <code>MarshalToml</code></p><p>看上去很简单是吧? 嗯, 是挺简单的. 但是其实这里是有坑的, 或者说, 实现的时候一定要注意一些细节.</p><p><code>Marshaler</code> 的实现一定要用普通的receiver, (即不要只实现 pointer receiver的), 因为pointer only 会导致如果是非指针形式的时候, 在序列化的时候无法调用到我们自己实现的方法.</p><p><code>Unmarshaler</code> 的实现一定要用 pointer receiver, 因为是解析数据到自身, 因此一定要修改自身, 不可修改是没有意义的.</p><p>举个例子, 假设我们想要JSON序列化一个自定义的int类型(主要用于作为enum的功能来用)为某些特定的string(主要用于JSON结构化日志的时候, 阅读更友好):</p><div class="relative"><pre><code class="code-highlight language-go"><span class="code-line"><span class="token keyword">type</span> HideType <span class="token builtin">int</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">const</span> <span class="token punctuation">(</span> </span><span class="code-line"> HideTypeNone HideType <span class="token operator">=</span> <span class="token number">0</span> </span><span class="code-line"> HideTypeLocation HideType <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> <span class="token number">0</span> </span><span class="code-line"> HideTypeAge HideType <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> <span class="token number">1</span> </span><span class="code-line"> HideTypeSex HideType <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> <span class="token number">2</span> </span><span class="code-line"> HideTypeNation HideType <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> <span class="token number">3</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">var</span> _hideTypeValuesMap <span class="token operator">=</span> <span class="token keyword">map</span><span class="token punctuation">[</span>HideType<span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span> </span><span class="code-line"> HideTypeNone<span class="token punctuation">:</span> <span class="token string">&quot;none&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> HideTypeLocation<span class="token punctuation">:</span> <span class="token string">&quot;location&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> HideTypeAge<span class="token punctuation">:</span> <span class="token string">&quot;age&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> HideTypeSex<span class="token punctuation">:</span> <span class="token string">&quot;sex&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> HideTypeNation<span class="token punctuation">:</span> <span class="token string">&quot;nation&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">var</span> _hideTypeValueToType <span class="token operator">=</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span>HideType<span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;none&quot;</span><span class="token punctuation">:</span> HideTypeNone<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;location&quot;</span><span class="token punctuation">:</span> HideTypeLocation<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;age&quot;</span><span class="token punctuation">:</span> HideTypeAge<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;sex&quot;</span><span class="token punctuation">:</span> HideTypeSex<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;nation&quot;</span><span class="token punctuation">:</span> HideTypeNation<span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token punctuation">(</span>ht HideType<span class="token punctuation">)</span> <span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> val<span class="token punctuation">,</span> ok <span class="token operator">:=</span> _hideTypeValuesMap<span class="token punctuation">[</span>ht<span class="token punctuation">]</span><span class="token punctuation">;</span> ok <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> val </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token string">&quot;unknown&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// MarshalJSON impl Marshaler interface https://pkg.go.dev/encoding/json#Marshaler</span> </span><span class="code-line"><span class="token keyword">func</span> <span class="token punctuation">(</span>ht HideType<span class="token punctuation">)</span> <span class="token function">MarshalJSON</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">byte</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token function">byte</span><span class="token punctuation">(</span>fmt<span class="token punctuation">.</span><span class="token function">Sprintf</span><span class="token punctuation">(</span>`<span class="token string">&quot;%v&quot;</span><span class="token string">`, ht.String())), nil </span></span><span class="code-line"><span class="token string">} </span></span><span class="code-line"><span class="token string"> </span></span><span class="code-line"><span class="token string">// UnmarshalJSON impl Unmarshaler interface </span></span><span class="code-line"><span class="token string">// https://pkg.go.dev/encoding/json#Unmarshaler </span></span><span class="code-line"><span class="token string">func (ht *HideType) UnmarshalJSON(rawJSON []byte) error { </span></span><span class="code-line"><span class="token string"> htStr := bytes.Trim(rawJSON, `</span>&quot;`<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> htInt<span class="token punctuation">,</span> ok <span class="token operator">:=</span> _hideTypeValueToType<span class="token punctuation">[</span><span class="token function">string</span><span class="token punctuation">(</span>htStr<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span> ok <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token operator">*</span>ht <span class="token operator">=</span> htInt </span><span class="code-line"> <span class="token keyword">return</span> <span class="token boolean">nil</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword">return</span> fmt<span class="token punctuation">.</span><span class="token function">Errorf</span><span class="token punctuation">(</span><span class="token string">&quot;parse into HideType failed, unknown HideType: %v&quot;</span><span class="token punctuation">,</span> htStr<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>没错, 整个实现非常简单, 对于 <code>MarshalJSON()</code> 我们只需要返回我们想要返回的 JSON string 即可. 注意这里一定要返回合法的JSON string类型. 这里使用了 <code>&quot;%v&quot;</code>, 而没有使用 <code>%q</code>, 主要是因为在我们的使用场景(类似enum)下100%确定不会有需要再次转义, 如果不确定的场景, 最好还是要用 <code>%q</code>.</p><p>UnmarshalJSON 我们由于确定输入是合法并且格式一定是特定的, 因此处理上也非常简单.不需要考虑过多.</p><h2 id="rust-实现"><a href="#rust-实现" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Rust 实现</h2><p>当然, serde 本身就可以处理这种序列化, 我们只需要加上<code>#[derive(Serialize, Deserialize, Debug)]</code> 即可. 这里特意用的自定义方式实现, 主要是从学习的角度.</p><p>序列化实现比较简单, Rust 里面我们只需要实现 <code>Serialize</code> trait 即可:</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token class-name type-definition">Serialize</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">serialize</span><span class="token operator">&lt;</span><span class="token class-name">S</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> serializer<span class="token punctuation">:</span> <span class="token class-name">S</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">S</span><span class="token punctuation">::</span><span class="token class-name">Ok</span><span class="token punctuation">,</span> <span class="token class-name">S</span><span class="token punctuation">::</span><span class="token class-name">Error</span><span class="token operator">&gt;</span> </span><span class="code-line"> <span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">S</span><span class="token punctuation">:</span> <span class="token class-name">Serializer</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>反序列化相对来说麻烦一些. 不像 Go 里面简单粗暴, 实现细节交给用户来处理, serde 里面需要按照 serde data model 来交换数据.</p><p>单从 <code>Deserialize</code> trait 来看, 好像反序列化也差不多. 但是实际上它还需要一个 Vistor trait</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token class-name type-definition">Deserialize</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;de</span><span class="token operator">&gt;</span><span class="token punctuation">:</span> <span class="token class-name">Sized</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">deserialize</span><span class="token operator">&lt;</span><span class="token class-name">D</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>deserializer<span class="token punctuation">:</span> <span class="token class-name">D</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token keyword">Self</span><span class="token punctuation">,</span> <span class="token class-name">D</span><span class="token punctuation">::</span><span class="token class-name">Error</span><span class="token operator">&gt;</span> </span><span class="code-line"> <span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">D</span><span class="token punctuation">:</span> <span class="token class-name">Deserializer</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;de</span><span class="token operator">&gt;</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>从语法上来说, <code>Visitor</code> trait 只有一个 <code>expecting</code> 方法是必须实现的, 但是实际使用中我们要根据具体的JSON 数据类型选择实现其它方法. 比如在我们这个例子中, 我们可以明确的确定, 我们收到的 JSON 数据是一个字符串类型的, 因此只需要<code>visit_str</code>, 注意 <code>visit_str</code> 比起 Golang 里面要用户手动解析 JSON 数据, serde 里面已经默认把数据给我们解析出来了, 所以, 当输入是 <code>&quot;foo&quot;</code> 的时候, 在 serde 里面我们<code>visit_str</code>得到的是 <code>foo</code>, 而在 Go 里面我们由于得到的是 <code>&quot;foo&quot;</code>, 因此还要自行处理外面的引号.</p><p>最后, 我们要将这个实现了 <code>Visitor</code> trait 的类型, 绑定到我们要反序列化的类型的<code>Deserialize</code> trait 上面: <code>deserializer.deserialize_str(HideTypeVisitor)</code></p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token class-name type-definition">Visitor</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;de</span><span class="token operator">&gt;</span><span class="token punctuation">:</span> <span class="token class-name">Sized</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">/// The value produced by this visitor.</span> </span><span class="code-line"> <span class="token keyword">type</span> <span class="token class-name type-definition">Value</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">/// Format a message stating what data this Visitor expects to receive.</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">expecting</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> formatter<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token namespace">fmt<span class="token punctuation">::</span></span><span class="token class-name">Formatter</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">fmt<span class="token punctuation">::</span></span><span class="token class-name">Result</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">/// ...</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>collections<span class="token punctuation">::</span></span><span class="token class-name">HashMap</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>fmt<span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">serde<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">Serialize</span><span class="token punctuation">,</span> <span class="token class-name">Deserialize</span><span class="token punctuation">,</span> <span class="token class-name">Serializer</span><span class="token punctuation">,</span> <span class="token class-name">Deserializer</span><span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">serde<span class="token punctuation">::</span>de<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">Error</span><span class="token punctuation">,</span> <span class="token class-name">Unexpected</span><span class="token punctuation">,</span> <span class="token class-name">Visitor</span><span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">once_cell<span class="token punctuation">::</span>sync<span class="token punctuation">::</span></span><span class="token class-name">Lazy</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token function">derive</span><span class="token punctuation">(</span><span class="token class-name">Copy</span><span class="token punctuation">,</span> <span class="token class-name">Clone</span><span class="token punctuation">,</span> <span class="token class-name">PartialEq</span><span class="token punctuation">,</span> <span class="token class-name">Eq</span><span class="token punctuation">,</span> <span class="token class-name">Hash</span><span class="token punctuation">,</span> <span class="token class-name">Debug</span><span class="token punctuation">)</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name type-definition">HideType</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name">HideTypeNone</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token class-name">HideTypeLocation</span> <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> <span class="token number">0</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token class-name">HideTypeAge</span> <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> <span class="token number">1</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token class-name">HideTypeSex</span> <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> <span class="token number">2</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token class-name">HideTypeNation</span> <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> <span class="token number">3</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">static</span> <span class="token constant">FILTER_TYPE_TO_NAME</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token class-name">HideType</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token class-name">HideType</span><span class="token punctuation">::</span><span class="token class-name">HideTypeNone</span><span class="token punctuation">,</span> <span class="token string">&quot;none&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token class-name">HideType</span><span class="token punctuation">::</span><span class="token class-name">HideTypeLocation</span><span class="token punctuation">,</span> <span class="token string">&quot;location&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token class-name">HideType</span><span class="token punctuation">::</span><span class="token class-name">HideTypeAge</span><span class="token punctuation">,</span> <span class="token string">&quot;age&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token class-name">HideType</span><span class="token punctuation">::</span><span class="token class-name">HideTypeSex</span><span class="token punctuation">,</span> <span class="token string">&quot;sex&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token class-name">HideType</span><span class="token punctuation">::</span><span class="token class-name">HideTypeNation</span><span class="token punctuation">,</span> <span class="token string">&quot;nation&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">]</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">static</span> <span class="token constant">TYPE_STR_MAP</span><span class="token punctuation">:</span> <span class="token class-name">Lazy</span><span class="token operator">&lt;</span><span class="token class-name">HashMap</span><span class="token operator">&lt;</span><span class="token class-name">HideType</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token operator">&gt;&gt;</span> <span class="token operator">=</span> <span class="token class-name">Lazy</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> m <span class="token operator">=</span> <span class="token class-name">HashMap</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">(</span>k<span class="token punctuation">,</span> v<span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token constant">FILTER_TYPE_TO_NAME</span><span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> m<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token operator">*</span>k<span class="token punctuation">,</span> <span class="token operator">*</span>v<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> m </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">static</span> <span class="token constant">STR_TYPE_MAP</span><span class="token punctuation">:</span> <span class="token class-name">Lazy</span><span class="token operator">&lt;</span><span class="token class-name">HashMap</span><span class="token operator">&lt;</span><span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span> <span class="token class-name">HideType</span><span class="token operator">&gt;&gt;</span> <span class="token operator">=</span> <span class="token class-name">Lazy</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> m <span class="token operator">=</span> <span class="token class-name">HashMap</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">(</span>k<span class="token punctuation">,</span> v<span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token constant">FILTER_TYPE_TO_NAME</span><span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> m<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token operator">*</span>v<span class="token punctuation">,</span> <span class="token operator">*</span>k<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> m </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">impl</span> <span class="token class-name">Serialize</span> <span class="token keyword">for</span> <span class="token class-name">HideType</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">serialize</span><span class="token operator">&lt;</span><span class="token class-name">S</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> serializer<span class="token punctuation">:</span> <span class="token class-name">S</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">S</span><span class="token punctuation">::</span><span class="token class-name">Ok</span><span class="token punctuation">,</span> <span class="token class-name">S</span><span class="token punctuation">::</span><span class="token class-name">Error</span><span class="token operator">&gt;</span> </span><span class="code-line"> <span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">S</span><span class="token punctuation">:</span> <span class="token class-name">Serializer</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token constant">TYPE_STR_MAP</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">serialize</span><span class="token punctuation">(</span>serializer<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name type-definition">HideTypeVisitor</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">impl</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;de</span><span class="token operator">&gt;</span> <span class="token class-name">Visitor</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;de</span><span class="token operator">&gt;</span> <span class="token keyword">for</span> <span class="token class-name">HideTypeVisitor</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">type</span> <span class="token class-name type-definition">Value</span> <span class="token operator">=</span> <span class="token class-name">HideType</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">expecting</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> formatter<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token namespace">fmt<span class="token punctuation">::</span></span><span class="token class-name">Formatter</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token namespace">fmt<span class="token punctuation">::</span></span><span class="token class-name">Result</span> <span class="token punctuation">{</span> </span><span class="code-line"> formatter<span class="token punctuation">.</span><span class="token function">write_str</span><span class="token punctuation">(</span><span class="token string">r#&quot;a string in one of: none, location, age, sex, nation&quot;#</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">visit_str</span><span class="token operator">&lt;</span><span class="token class-name">E</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">,</span> v<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">Value</span><span class="token punctuation">,</span> <span class="token class-name">E</span><span class="token operator">&gt;</span> </span><span class="code-line"> <span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">E</span><span class="token punctuation">:</span> <span class="token class-name">Error</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">match</span> <span class="token constant">STR_TYPE_MAP</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name">Some</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token operator">*</span>t<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token class-name">None</span> <span class="token operator">=&gt;</span> <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token class-name">E</span><span class="token punctuation">::</span><span class="token function">invalid_value</span><span class="token punctuation">(</span><span class="token class-name">Unexpected</span><span class="token punctuation">::</span><span class="token class-name">Str</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">impl</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;de</span><span class="token operator">&gt;</span> <span class="token class-name">Deserialize</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;de</span><span class="token operator">&gt;</span> <span class="token keyword">for</span> <span class="token class-name">HideType</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">deserialize</span><span class="token operator">&lt;</span><span class="token class-name">D</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>deserializer<span class="token punctuation">:</span> <span class="token class-name">D</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">HideType</span><span class="token punctuation">,</span> <span class="token class-name">D</span><span class="token punctuation">::</span><span class="token class-name">Error</span><span class="token operator">&gt;</span> </span><span class="code-line"> <span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">D</span><span class="token punctuation">:</span> <span class="token class-name">Deserializer</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;de</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> deserializer<span class="token punctuation">.</span><span class="token function">deserialize_str</span><span class="token punctuation">(</span><span class="token class-name">HideTypeVisitor</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>当然, 这里也并不一定要用到 hashmap, 直接用 match 处理从类型到 string的转换也是可以的. 不过通过 hashmap 的方式会比较自然, 并且我们不再需要手动去维护一个正向和反向的 map 了.</p><p>总体来说, Golang 里面实现自定义序列化和反序列化, 比较直接和简单粗暴. 整个接口的定义也非常简单. 而 Rust 里的 serde 则有很多功能和功能. 首先你一定要了解的是 serde data model. 相比于 Golang 里面直接用 Go 的类型, 并且其默认实现直接将 Go 的类型, 比如 []byte 绑定到其实现上 ([]byte类型的数据在序列化后会被Golang转换成base64的表现形式). serde 里面是通过 serde data model 来实现数据映射的. 而 serde 本身是一个框架, 并不负责实现, 其实现由扩展提供, 如 serde_json, serde_yaml 等. 所以 serde 的好处是, trait 是统一的, 而 Go 里面则是各实现各的, 比如官方实现了 JSON, <a href="https://github.com/go-yaml/yaml/blob/f6f7691b1fdeb513f56608cd2c32c51f8194bf51/yaml.go#L36">第三方实现了 YAML</a> 等.</p><p>比如 yaml:</p><div class="relative"><pre><code class="code-highlight language-go"><span class="code-line"><span class="token function">UnmarshalYAML</span><span class="token punctuation">(</span>value <span class="token operator">*</span>Node<span class="token punctuation">)</span> <span class="token builtin">error</span> </span></code></pre></div><p>官方 JSON:</p><div class="relative"><pre><code class="code-highlight language-go"><span class="code-line"><span class="token function">UnmarshalJSON</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">byte</span><span class="token punctuation">)</span> <span class="token builtin">error</span> </span></code></pre></div><p>可以看到, 虽然命名和参数样子差不多, 但是实际上还是不一样, 当然, 官方也并没有任何规范说明要一样. 实际上也不能做成一样, 假设 json 和 yaml 的 Unmarshaler interface 都定义为 <code>Unmarshal([]byte) error</code>, 由于 Go 的 interface 是鸭子类型, 这会导致错误的断言.</p><p>另外一点就是, 由于 serde 是一个框架, 而我们的自定义序列化也是映射到框架的数据模型, 因此是跟语言(json, yaml, toml 等)无关的. 可以做到一次定义, 到处运行. 而 Golang 的自定义序列化一定是针对某个类型的(比如 JSON), 上面的示例, 如果换成 yaml, 还得重新实现一次, 而 serde 则不存在这个问题.</p><p>2022-07-27 补充:</p><p>还有一点就是序列化字段重命名, golang 是通过给 struct 打 tag 的方式, 不同的语言需要不同的tag, 如何解析这个 tag 是序列化mod所负责的工作, 比如 json 用的是 `json`, yaml 用的是 `yaml`, 而数据库相关的 gorm 用的是 `gorm`, 因此从这一点来说, golang 的 struct tag 并不是专门用于序列化. 还可以用在其它地方.</p><p>而 Rust 的字段重命名是在框架层面的, 也就是说, 指定了rename后, 无论是 json 还是 yaml 都会按照这个来, 优点是不必要重复地添加很多 tag. (对比: golang 一个 struct 要同时加上 json, yaml, toml 甚至 bson 的 tag, 就显得很没有可读性, 但是如果你不加, 有些字段可能序列化出来不是你要的结果, 比如 ID 在 mongodb 里面要用 `_id` )</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://pkg.go.dev/encoding/json#Marshaler">https://pkg.go.dev/encoding/json#Marshaler</a></p><p><a href="https://pkg.go.dev/encoding/json#Unmarshaler">https://pkg.go.dev/encoding/json#Unmarshaler</a></p><p><a href="https://serde.rs/data-model.html">https://serde.rs/data-model.html</a></p><p><a href="https://serde.rs/impl-serialize.html">https://serde.rs/impl-serialize.html</a></p><p><a href="https://serde.rs/impl-deserialize.html">https://serde.rs/impl-deserialize.html</a></p> Sun, 24 Jul 2022 16:39:45 GMT ttyS3 rustserdejson https://ttys3.dev/blog/use-giscus-as-comment-system 使用giscus作为评论系统 https://ttys3.dev/blog/use-giscus-as-comment-system <p>giscus: A comments system powered by <a href="https://docs.github.com/en/discussions">GitHub Discussions</a></p><p>老灯之前用的是 utteranc.es, 这个是基于 Github issue 功能实现的.</p><p>giscus 是基于 discussion, 简单试用了一下, 最明显的区别回复的功能吧. 可以直接在某个评论下面回复.</p><p>第二就是支持reaction.</p><div><img alt="" src="https://ttys3.dev/static/assets/giscus-2022-07-25_00-35-YHTHH6TZ.png" width="1723" height="1657"/></div><p>新建一个专门的仓库用来做评论用即可. 具体做法很简单:</p><p>Choose the repository giscus will connect to. Make sure that:</p><ol><li>The <strong>repository is <a href="https://docs.github.com/en/github/administering-a-repository/managing-repository-settings/setting-repository-visibility#making-a-repository-public">public</a></strong>, otherwise visitors will not be able to view the discussion.</li><li>The <strong><a href="https://github.com/apps/giscus">giscus</a> app is installed</strong>, otherwise visitors will not be able to comment and react.</li><li>The <strong>Discussions feature is turned on</strong> by <a href="https://docs.github.com/en/github/administering-a-repository/managing-repository-settings/enabling-or-disabling-github-discussions-for-a-repository">enabling it for your repository</a>.</li></ol><p>comments.html</p><div class="relative"><pre><code class="code-highlight language-go"><span class="code-line"><span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> giscus https<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>giscus<span class="token punctuation">.</span>vercel<span class="token punctuation">.</span>app<span class="token operator">/</span> <span class="token operator">--</span><span class="token operator">&gt;</span> </span><span class="code-line"><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token keyword">if</span> and <span class="token punctuation">(</span><span class="token punctuation">.</span>Params<span class="token punctuation">.</span>comments<span class="token punctuation">)</span> <span class="token punctuation">(</span>ne <span class="token string">&quot;&quot;</span> $<span class="token punctuation">.</span>Site<span class="token punctuation">.</span>Params<span class="token punctuation">.</span>giscus<span class="token punctuation">.</span>dataRepo<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> </span><span class="code-line"><span class="token operator">&lt;</span>script src<span class="token operator">=</span><span class="token string">&quot;https://giscus.app/client.js&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>repo<span class="token operator">=</span><span class="token string">&quot;{{ $.Site.Params.giscus.dataRepo }}&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>repo<span class="token operator">-</span>id<span class="token operator">=</span><span class="token string">&quot;{{ $.Site.Params.giscus.dataRepoID }}&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>category<span class="token operator">=</span><span class="token string">&quot;{{ $.Site.Params.giscus.dataCategory }}&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>category<span class="token operator">-</span>id<span class="token operator">=</span><span class="token string">&quot;{{ $.Site.Params.giscus.dataCategoryID }}&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>mapping<span class="token operator">=</span><span class="token string">&quot;pathname&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>strict<span class="token operator">=</span><span class="token string">&quot;0&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>reactions<span class="token operator">-</span>enabled<span class="token operator">=</span><span class="token string">&quot;1&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>emit<span class="token operator">-</span>metadata<span class="token operator">=</span><span class="token string">&quot;0&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>input<span class="token operator">-</span>position<span class="token operator">=</span><span class="token string">&quot;bottom&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>theme<span class="token operator">=</span><span class="token string">&quot;dark_protanopia&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>lang<span class="token operator">=</span><span class="token string">&quot;en&quot;</span> </span><span class="code-line"> data<span class="token operator">-</span>loading<span class="token operator">=</span><span class="token string">&quot;lazy&quot;</span> </span><span class="code-line"> crossorigin<span class="token operator">=</span><span class="token string">&quot;anonymous&quot;</span> </span><span class="code-line"> async<span class="token operator">&gt;</span> </span><span class="code-line"><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">&gt;</span> </span><span class="code-line"><span class="token punctuation">{</span><span class="token punctuation">{</span> end <span class="token punctuation">}</span><span class="token punctuation">}</span> </span></code></pre></div><p>配置:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token literal-property property">params</span><span class="token operator">:</span> </span><span class="code-line"> <span class="token literal-property property">giscus</span><span class="token operator">:</span> </span><span class="code-line"> <span class="token literal-property property">dataRepo</span><span class="token operator">:</span> <span class="token string">&#x27;&#x27;</span> </span><span class="code-line"> <span class="token literal-property property">dataRepoID</span><span class="token operator">:</span> <span class="token string">&quot;R_xxxxxxxxxx&quot;</span> </span><span class="code-line"> <span class="token literal-property property">dataCategory</span><span class="token operator">:</span> <span class="token string">&quot;General&quot;</span> </span><span class="code-line"> <span class="token literal-property property">dataCategoryID</span><span class="token operator">:</span> <span class="token string">&quot;DIC_xxxxxxxxx&quot;</span> </span></code></pre></div><p>注意, 这些配置参数都是 <a href="https://giscus.vercel.app/">https://giscus.vercel.app/</a> 自动生成了.</p> Sun, 24 Jul 2022 16:24:07 GMT ttyS3 hugocomment https://ttys3.dev/blog/fixup-intellij-scheme 简单修复 intellij-scheme https://ttys3.dev/blog/fixup-intellij-scheme <p>tree-sitter 的 highlights.scm 是 S 表达式, 最近安装了 intellij-scheme, 主要是看个高亮.</p><p>然后发现它天天 panic, 这个插件当前的发布者也是 fork 了前人的, 看样子也没什么人维护.</p><p>于是决定简单地处理一下, 至少能看个高亮吧.</p><h2 id="dirty-and-quick-fix-up"><a href="#dirty-and-quick-fix-up" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Dirty and quick fix up</h2><p>关于 JDK 版本, 注意, <a href="https://plugins.jetbrains.com/docs/intellij/setting-up-environment.html#configuring-intellij-platform-sdk">https://plugins.jetbrains.com/docs/intellij/setting-up-environment.html#configuring-intellij-platform-sdk</a> 有专门强调:</p><ul><li>Set up a required Java SDK. See the <em>IntelliJ Build Configuration</em> section of <a href="https://upsource.jetbrains.com/idea-ce/file/idea-ce-4d741bc560dd19306d4624d7c8a88aea537f4e6f/README.md">Check Out And Build Community Edition</a> for instructions about creating <strong>1.8</strong> (<strong>11</strong> when targeting 2020.3 or later) Java SDK.</li></ul><blockquote><p>Do not use a more recent Java version than the one specified.</p></blockquote><p>Arch 自带的默认已经是 JDK 18 了. 这里我们需要安装 JDK 11.</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line">paru <span class="token operator">-</span><span class="token constant">S</span> jdk11<span class="token operator">-</span>openjdk </span><span class="code-line"> </span><span class="code-line"># 找到 jdk 的 <span class="token constant">JAVA_HOME</span> 为 <span class="token operator">/</span>usr<span class="token operator">/</span>lib<span class="token operator">/</span>jvm<span class="token operator">/</span>java<span class="token operator">-</span><span class="token number">11</span><span class="token operator">-</span>openjdk<span class="token operator">/</span> </span><span class="code-line">paru <span class="token operator">-</span><span class="token maybe-class-name">Qlv</span> jdk11<span class="token operator">-</span>openjdk <span class="token operator">|</span> grep <span class="token operator">-</span>i <span class="token operator">/</span>bin<span class="token operator">/</span>java </span><span class="code-line"> </span><span class="code-line"> </span></code></pre></div><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line">update failed <span class="token keyword control-flow">for</span> <span class="token function"><span class="token maybe-class-name">AnAction</span></span><span class="token punctuation">(</span>schemely<span class="token punctuation">.</span><span class="token property-access">repl</span><span class="token punctuation">.</span><span class="token property-access">toolwindow</span><span class="token punctuation">.</span><span class="token property-access">actions</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">NewInProcessConsoleAction</span></span><span class="token punctuation">,</span> id<span class="token operator">=</span>schemely<span class="token punctuation">.</span><span class="token property-access">repl</span><span class="token punctuation">.</span><span class="token property-access">toolwindow</span><span class="token punctuation">.</span><span class="token property-access">actions</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">NewInProcessConsoleAction</span></span><span class="token punctuation">)</span> <span class="token keyword">with</span> text<span class="token operator">=</span><span class="token maybe-class-name">Start</span> <span class="token maybe-class-name">In</span><span class="token operator">-</span><span class="token maybe-class-name">Process</span> <span class="token maybe-class-name">Scheme</span> <span class="token maybe-class-name">Console</span> </span><span class="code-line"> </span><span class="code-line">java<span class="token punctuation">.</span><span class="token property-access">lang</span><span class="token punctuation">.</span><span class="token class-name known-class-name">NoClassDefFoundError</span><span class="token operator">:</span> com<span class="token operator">/</span>intellij<span class="token operator">/</span>openapi<span class="token operator">/</span>actionSystem<span class="token operator">/</span><span class="token maybe-class-name">DataKeys</span> </span><span class="code-line"> at schemely<span class="token punctuation">.</span><span class="token property-access">utils</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Actions</span></span><span class="token punctuation">.</span><span class="token property-access function method">getModule</span><span class="token punctuation">(</span><span class="token maybe-class-name">Actions</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line"> at schemely<span class="token punctuation">.</span><span class="token property-access">repl</span><span class="token punctuation">.</span><span class="token property-access">toolwindow</span><span class="token punctuation">.</span><span class="token property-access">actions</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">NewInProcessConsoleAction</span></span><span class="token punctuation">.</span><span class="token property-access function method">update</span><span class="token punctuation">(</span><span class="token maybe-class-name">NewInProcessConsoleAction</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">24</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">actionSystem</span><span class="token punctuation">.</span><span class="token property-access">ex</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ActionUtil</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$performDumbAwareUpdate$0</span><span class="token punctuation">(</span><span class="token maybe-class-name">ActionUtil</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">131</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">actionSystem</span><span class="token punctuation">.</span><span class="token property-access">ex</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ActionUtil</span></span><span class="token punctuation">.</span><span class="token property-access function method">performDumbAwareUpdate</span><span class="token punctuation">(</span><span class="token maybe-class-name">ActionUtil</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">145</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">actionSystem</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ActionUpdater</span></span><span class="token punctuation">.</span><span class="token property-access function method">doUpdate</span><span class="token punctuation">(</span><span class="token maybe-class-name">ActionUpdater</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">639</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">actionSystem</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ActionUpdater</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$updateActionReal$4</span><span class="token punctuation">(</span><span class="token maybe-class-name">ActionUpdater</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">125</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">actionSystem</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ActionUpdater</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$computeOnEdt$6</span><span class="token punctuation">(</span><span class="token maybe-class-name">ActionUpdater</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">209</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$runProcess$0</span><span class="token punctuation">(</span><span class="token maybe-class-name">ProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">58</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CoreProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$runProcess$2</span><span class="token punctuation">(</span><span class="token maybe-class-name">CoreProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">189</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CoreProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$executeProcessUnderProgress$12</span><span class="token punctuation">(</span><span class="token maybe-class-name">CoreProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">608</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CoreProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">registerIndicatorAndRun</span><span class="token punctuation">(</span><span class="token maybe-class-name">CoreProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">683</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CoreProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">computeUnderProgress</span><span class="token punctuation">(</span><span class="token maybe-class-name">CoreProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">639</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CoreProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">executeProcessUnderProgress</span><span class="token punctuation">(</span><span class="token maybe-class-name">CoreProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">607</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ProgressManagerImpl</span></span><span class="token punctuation">.</span><span class="token property-access function method">executeProcessUnderProgress</span><span class="token punctuation">(</span><span class="token maybe-class-name">ProgressManagerImpl</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">60</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CoreProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">runProcess</span><span class="token punctuation">(</span><span class="token maybe-class-name">CoreProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">176</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">runProcess</span><span class="token punctuation">(</span><span class="token maybe-class-name">ProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">58</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">actionSystem</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ActionUpdater</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$computeOnEdt$7</span><span class="token punctuation">(</span><span class="token maybe-class-name">ActionUpdater</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">207</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">actionSystem</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ActionUpdateEdtExecutor</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$computeOnEdt$0</span><span class="token punctuation">(</span><span class="token maybe-class-name">ActionUpdateEdtExecutor</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">45</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">application</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">TransactionGuardImpl$1</span></span><span class="token punctuation">.</span><span class="token property-access function method">run</span><span class="token punctuation">(</span><span class="token maybe-class-name">TransactionGuardImpl</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">application</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ApplicationImpl</span></span><span class="token punctuation">.</span><span class="token property-access function method">runIntendedWriteActionOnCurrentThread</span><span class="token punctuation">(</span><span class="token maybe-class-name">ApplicationImpl</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">873</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">application</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ApplicationImpl$3</span></span><span class="token punctuation">.</span><span class="token property-access function method">run</span><span class="token punctuation">(</span><span class="token maybe-class-name">ApplicationImpl</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">511</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">application</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">FlushQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">doRun</span><span class="token punctuation">(</span><span class="token maybe-class-name">FlushQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">69</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">application</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">FlushQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">runNextEvent</span><span class="token punctuation">(</span><span class="token maybe-class-name">FlushQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">112</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">application</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">FlushQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">flushNow</span><span class="token punctuation">(</span><span class="token maybe-class-name">FlushQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">42</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access">event</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">InvocationEvent</span></span><span class="token punctuation">.</span><span class="token property-access function method">dispatch</span><span class="token punctuation">(</span><span class="token maybe-class-name">InvocationEvent</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">313</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">dispatchEventImpl</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">776</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventQueue$4</span></span><span class="token punctuation">.</span><span class="token property-access function method">run</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">727</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventQueue$4</span></span><span class="token punctuation">.</span><span class="token property-access function method">run</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">721</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">base</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">security</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">AccessController</span></span><span class="token punctuation">.</span><span class="token property-access function method">doPrivileged</span><span class="token punctuation">(</span><span class="token maybe-class-name">Native</span> <span class="token maybe-class-name">Method</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">base</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">security</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ProtectionDomain$JavaSecurityAccessImpl</span></span><span class="token punctuation">.</span><span class="token property-access function method">doIntersectionPrivilege</span><span class="token punctuation">(</span><span class="token maybe-class-name">ProtectionDomain</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">85</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">dispatchEvent</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">746</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">ide</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">IdeEventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">defaultDispatchEvent</span><span class="token punctuation">(</span><span class="token maybe-class-name">IdeEventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">898</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">ide</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">IdeEventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">_dispatchEvent</span><span class="token punctuation">(</span><span class="token maybe-class-name">IdeEventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">746</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">ide</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">IdeEventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$dispatchEvent$6</span><span class="token punctuation">(</span><span class="token maybe-class-name">IdeEventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">439</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">progress</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">CoreProgressManager</span></span><span class="token punctuation">.</span><span class="token property-access function method">computePrioritized</span><span class="token punctuation">(</span><span class="token maybe-class-name">CoreProgressManager</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">803</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">ide</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">IdeEventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$dispatchEvent$7</span><span class="token punctuation">(</span><span class="token maybe-class-name">IdeEventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">438</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">application</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">TransactionGuardImpl</span></span><span class="token punctuation">.</span><span class="token property-access function method">performActivity</span><span class="token punctuation">(</span><span class="token maybe-class-name">TransactionGuardImpl</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">106</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">ide</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">IdeEventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">performActivity</span><span class="token punctuation">(</span><span class="token maybe-class-name">IdeEventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">604</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">ide</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">IdeEventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">lambda$dispatchEvent$8</span><span class="token punctuation">(</span><span class="token maybe-class-name">IdeEventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">436</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">application</span><span class="token punctuation">.</span><span class="token property-access">impl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ApplicationImpl</span></span><span class="token punctuation">.</span><span class="token property-access function method">runIntendedWriteActionOnCurrentThread</span><span class="token punctuation">(</span><span class="token maybe-class-name">ApplicationImpl</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">873</span><span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">ide</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">IdeEventQueue</span></span><span class="token punctuation">.</span><span class="token property-access function method">dispatchEvent</span><span class="token punctuation">(</span><span class="token maybe-class-name">IdeEventQueue</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">484</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventDispatchThread</span></span><span class="token punctuation">.</span><span class="token property-access function method">pumpOneEventForFilters</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventDispatchThread</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">207</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventDispatchThread</span></span><span class="token punctuation">.</span><span class="token property-access function method">pumpEventsForFilter</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventDispatchThread</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">128</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventDispatchThread</span></span><span class="token punctuation">.</span><span class="token property-access function method">pumpEventsForHierarchy</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventDispatchThread</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">117</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventDispatchThread</span></span><span class="token punctuation">.</span><span class="token property-access function method">pumpEvents</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventDispatchThread</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">113</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventDispatchThread</span></span><span class="token punctuation">.</span><span class="token property-access function method">pumpEvents</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventDispatchThread</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">105</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">desktop</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">awt</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">EventDispatchThread</span></span><span class="token punctuation">.</span><span class="token property-access function method">run</span><span class="token punctuation">(</span><span class="token maybe-class-name">EventDispatchThread</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">92</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token maybe-class-name">Caused</span> by<span class="token operator">:</span> java<span class="token punctuation">.</span><span class="token property-access">lang</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ClassNotFoundException</span></span><span class="token operator">:</span> com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">openapi</span><span class="token punctuation">.</span><span class="token property-access">actionSystem</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">DataKeys</span></span> <span class="token function"><span class="token maybe-class-name">PluginClassLoader</span></span><span class="token punctuation">(</span>plugin<span class="token operator">=</span><span class="token function"><span class="token maybe-class-name">PluginDescriptor</span></span><span class="token punctuation">(</span>name<span class="token operator">=</span><span class="token maybe-class-name">Scheme</span><span class="token punctuation">,</span> id<span class="token operator">=</span>intellij<span class="token operator">-</span>scheme<span class="token punctuation">,</span> descriptorPath<span class="token operator">=</span>plugin<span class="token punctuation">.</span><span class="token property-access">xml</span><span class="token punctuation">,</span> path<span class="token operator">=</span><span class="token operator">~</span><span class="token operator">/</span><span class="token punctuation">.</span><span class="token property-access">local</span><span class="token operator">/</span>share<span class="token operator">/</span><span class="token maybe-class-name">JetBrains</span><span class="token operator">/</span><span class="token maybe-class-name">Toolbox</span><span class="token operator">/</span>apps<span class="token operator">/</span><span class="token maybe-class-name">CLion</span><span class="token operator">/</span>ch<span class="token operator">-</span><span class="token number">0</span><span class="token operator">/</span><span class="token number">221.5080</span><span class="token number">.224</span><span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token operator">/</span>intellij<span class="token operator">-</span>scheme<span class="token punctuation">,</span> version<span class="token operator">=</span><span class="token number">0.1</span><span class="token number">.6</span><span class="token punctuation">,</span> <span class="token keyword">package</span><span class="token operator">=</span><span class="token keyword nil null">null</span><span class="token punctuation">,</span> isBundled<span class="token operator">=</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">,</span> packagePrefix<span class="token operator">=</span><span class="token keyword nil null">null</span><span class="token punctuation">,</span> instanceId<span class="token operator">=</span><span class="token number">15</span><span class="token punctuation">,</span> state<span class="token operator">=</span>active<span class="token punctuation">)</span> </span><span class="code-line"> at com<span class="token punctuation">.</span><span class="token property-access">intellij</span><span class="token punctuation">.</span><span class="token property-access">ide</span><span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">cl</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">PluginClassLoader</span></span><span class="token punctuation">.</span><span class="token property-access function method">loadClass</span><span class="token punctuation">(</span><span class="token maybe-class-name">PluginClassLoader</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">215</span><span class="token punctuation">)</span> </span><span class="code-line"> at java<span class="token punctuation">.</span><span class="token property-access">base</span><span class="token operator">/</span>java<span class="token punctuation">.</span><span class="token property-access">lang</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">ClassLoader</span></span><span class="token punctuation">.</span><span class="token property-access function method">loadClass</span><span class="token punctuation">(</span><span class="token maybe-class-name">ClassLoader</span><span class="token punctuation">.</span><span class="token property-access">java</span><span class="token operator">:</span><span class="token number">522</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token operator spread">...</span> <span class="token number">47</span> more </span></code></pre></div><p>由于时间有限, 而且我只是要年高亮而已. 简单修复了下, 移除了 REPL 相关代码. 顺利通过编译.</p><p><a href="https://github.com/ttys3/intellij-scheme/releases/tag/v0.1.7">https://github.com/ttys3/intellij-scheme/releases/tag/v0.1.7</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://plugins.jetbrains.com/docs/intellij/getting-started.html#using-devkit">https://plugins.jetbrains.com/docs/intellij/getting-started.html#using-devkit</a></p><p><a href="https://plugins.jetbrains.com/docs/intellij/setting-up-environment.html#configuring-intellij-platform-sdk">https://plugins.jetbrains.com/docs/intellij/setting-up-environment.html#configuring-intellij-platform-sdk</a></p><p><a href="https://plugins.jetbrains.com/docs/intellij/creating-plugin-project.html#adding-code-to-the-project">https://plugins.jetbrains.com/docs/intellij/creating-plugin-project.html#adding-code-to-the-project</a></p><p><a href="https://plugins.jetbrains.com/docs/intellij/deploying-plugin.html">https://plugins.jetbrains.com/docs/intellij/deploying-plugin.html</a></p> Mon, 25 Apr 2022 16:04:58 GMT ttyS3 jetbrainsjava https://ttys3.dev/blog/fedora-36-installation Fedora 36 Installation https://ttys3.dev/blog/fedora-36-installation <p>F36 当前已经 Beta, 不出意外, 4月份应该会正式发布.</p><p>由于发现磁盘还有一点空闲空间, 想来可以装一个 F36 玩玩. 主要是想体验它的<a href="https://fedoraproject.org/wiki/Changes/BtrfsByDefault">默认 btrfs 文件系统</a>.</p><p>从 <a href="https://fedoraproject.org/wiki/Releases/33" title="Releases/33">Fedora 33</a> 起, btrfs 就已经是Fedora Linux 桌面版本的默认文件系统, 但是老灯当时是从 Fedora 31 升级的, 由于F33之前都是默认 ext4, 因此, 即使升级到 F33, 也还是用的 ext4.</p><h2 id="安装配置"><a href="#安装配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装配置</h2><p>整个安装过程还是非常顺利的, 并且安装过程比较简单, 点两下鼠标就搞定了.</p><p>安装后第一次进系统会要求创建第一个用户, 然后是有个启用第三方源(主要是 rpmfusion) 的选项, 默认是蓝色启用的.</p><p>所以 rpmfusion 也不用单独安装了.</p><p>默认的分区方案是一个 btrfs root volume, 然后 <code>/</code> 用 <code>/root</code> subvolume, <code>/home</code> 用 <code>/home</code> subvolume, 同时 <code>/boot</code> 使用单独分区, 且保持使用 ext4:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token punctuation">[</span>ttys3@fedora ~<span class="token punctuation">]</span>$ <span class="token function">mount</span> <span class="token operator">|</span> rg <span class="token string">&#x27;btrfs|ext4|vfat&#x27;</span> </span><span class="code-line">/dev/nvme0n1p5 on / <span class="token class-name builtin">type</span> btrfs <span class="token punctuation">(</span>rw,relatime,seclabel,compress<span class="token operator">=</span>zstd:1,ssd,space_cache<span class="token operator">=</span>v2,subvolid<span class="token operator">=</span><span class="token number">257</span>,subvol<span class="token operator">=</span>/root<span class="token punctuation">)</span> </span><span class="code-line">/dev/nvme0n1p5 on /home <span class="token class-name builtin">type</span> btrfs <span class="token punctuation">(</span>rw,relatime,seclabel,compress<span class="token operator">=</span>zstd:1,ssd,space_cache<span class="token operator">=</span>v2,subvolid<span class="token operator">=</span><span class="token number">256</span>,subvol<span class="token operator">=</span>/home<span class="token punctuation">)</span> </span><span class="code-line">/dev/nvme0n1p4 on /boot <span class="token class-name builtin">type</span> ext4 <span class="token punctuation">(</span>rw,relatime,seclabel<span class="token punctuation">)</span> </span><span class="code-line">/dev/nvme0n1p1 on /boot/efi <span class="token class-name builtin">type</span> vfat <span class="token punctuation">(</span>rw,relatime,fmask<span class="token operator">=</span>0077,dmask<span class="token operator">=</span>0077,codepage<span class="token operator">=</span><span class="token number">437</span>,iocharset<span class="token operator">=</span>ascii,shortname<span class="token operator">=</span>winnt,errors<span class="token operator">=</span>remount-ro<span class="token punctuation">)</span> </span></code></pre></div><p>第一件事, 我们要调整一下 dnf 配置 <code>/etc/dnf/dnf.conf</code></p><p>增加 <code>max_parallel_downloads=8</code> 或 <code>max_parallel_downloads=16</code> (主要看你网速)</p><p>第一次启动后, `sudo dnf upgrade -y` 更新系统到最新内核并重启 (主要是为了后面安装显卡驱动).</p><p>nvidia 专有驱动安装</p><p>重启后, 我们先把显卡驱动安装了. 默认启动时加载的是 <code>nouveau</code> 开源驱动. 4K 屏 流畅度一般, 切成 专有驱动丝滑.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> akmod-nvidia <span class="token parameter variable">-y</span> </span></code></pre></div><p>成功安装 nvidia 驱动后再重启一次系统.</p><p>好了, 再次重启后, 我们 <code>cat /proc/cmdline</code> 验证下 n 卡驱动的内核参数是不是正常, 主要驱动就是添加了 <code>rd.driver.blacklist=nouveau modprobe.blacklist=nouveau nvidia-drm.modeset=1</code>, 即屏蔽开源驱动<code>nouveau</code>, 并启用 nvidia_drm 内核模块的 modeset (即 KMS)</p><p>老灯还有个习惯就是, 编辑 <code>/etc/default/grub</code>, 并删除 <code>rhgb</code>, 修改 <code>quiet</code> 为 <code>noquiet</code>. (需要<code>sudo grub2-mkconfig -o /etc/grub2-efi.cfg</code> 然后重启的时候才能看到效果)</p><p>在老灯看来, <code>rhgb</code> 不利于排查问题. (当系统真出现问题的时候, 你两眼一摸黑, 不知道卡在哪一步了)</p><p>Google Chrome 的安装方法参考 <a href="https://docs.fedoraproject.org/en-US/quick-docs/installing-chromium-or-google-chrome-browsers/">https://docs.fedoraproject.org/en-US/quick-docs/installing-chromium-or-google-chrome-browsers/</a></p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># Install Third Party Repositories</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> fedora-workstation-repositories </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Enable the Google Chrome repo</span> </span><span class="code-line"><span class="token function">sudo</span> dnf config-manager --set-enabled google-chrome </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Finally, install Chrome</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> google-chrome-stable </span></code></pre></div><p>安装 zsh 并设置为 login shell:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token parameter variable">-y</span> <span class="token function">zsh</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 给 root 改:</span> </span><span class="code-line"><span class="token comment"># 提示时输入 /usr/bin/zsh</span> </span><span class="code-line"><span class="token function">sudo</span> lchsh </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 给当自己的用户名改:</span> </span><span class="code-line"><span class="token comment"># 提示时输入 /usr/bin/zsh</span> </span><span class="code-line"><span class="token function">sudo</span> lchsh username </span></code></pre></div><p>安装一些必要小工具:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dnf <span class="token function">install</span> <span class="token parameter variable">-y</span> ripgrep <span class="token function">htop</span> nload ncdu neovim xlsclients neofetch gedit gnome-tweaks </span></code></pre></div><p>安装完整版的 java:</p><p>Fedora 有个坏毛病就是, 默认安装的是 headless 版的 openjdk (F36 是 <code>java-17-openjdk-headless</code>), 如果需要 GUI 支持, 还要安装 另一个包. 如果不安装, 你在运行基于 JAVA 的 GUI 程序时可能会遇到<a href="https://ask.fedoraproject.org/t/java-cant-find-library/10128"> &quot;Can’t load library libawt_xawt.so&quot; 的错误</a></p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token punctuation">[</span>root@fedora yum.repos.d<span class="token punctuation">]</span><span class="token comment"># dnf list --installed | rg java</span> </span><span class="code-line">abrt-java-connector.x86_64 <span class="token number">1.3</span>.1-3.fc36 @anaconda </span><span class="code-line">java-17-openjdk-headless.x86_64 <span class="token number">1</span>:17.0.2.0.8-7.fc36 @anaconda </span><span class="code-line">javapackages-filesystem.noarch <span class="token number">6.0</span>.0-7.fc36 @anaconda </span><span class="code-line">tzdata-java.noarch 2022a-1.fc36 @fedora </span></code></pre></div><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token parameter variable">-y</span> java-17-openjdk </span></code></pre></div><p><a href="https://fedoraproject.org/wiki/Changes/UseNanoByDefault">F33 起 Fedora 的默认编辑器就成了 nano 了</a>, 如果你想恢复 vim 为默认编辑器, 下面的命令会安装vim为默认编辑器并卸载nano--default-editor 包.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> vim-default-editor <span class="token parameter variable">--allowerasing</span> </span></code></pre></div><p>输入法安装, 我习惯五笔:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token parameter variable">-y</span> ibus-rime ibus-table-chinese-wubi-jidian </span><span class="code-line"> </span><span class="code-line"><span class="token function">git</span> clone https://github.com/ttys3/rime-wubi <span class="token constant environment">$HOME</span>/.config/ibus/rime </span></code></pre></div><p>using <code>ibus-setup</code> and add <code>Chinese - Rime</code> and <code>English - English</code> Input Method</p><p>go to Gnome <code>Keyboard</code> add <code>Chinese(Rime)</code></p><p>编辑 <code>/etc/environment</code> 加上:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">GTK_IM_MODULE</span><span class="token operator">=</span>ibus </span><span class="code-line"><span class="token constant">QT_IM_MODULE</span><span class="token operator">=</span>ibus </span><span class="code-line"><span class="token constant">XMODIFIERS</span><span class="token operator">=</span>@im<span class="token operator">=</span>ibus </span><span class="code-line"><span class="token constant">INPUT_METHOD</span><span class="token operator">=</span>ibus </span><span class="code-line"><span class="token constant">SDL_IM_MODULE</span><span class="token operator">=</span>ibus </span><span class="code-line"><span class="token constant">GLFW_IM_MODULE</span><span class="token operator">=</span>ibus </span></code></pre></div><p>编译安装 neovim 最新版 (注: 也可以使用 <code>sudo dnf builddep neovim</code> 安装构建依赖):</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf groupinstall <span class="token string">&quot;Development Tools&quot;</span> <span class="token string">&quot;Development Libraries&quot;</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token parameter variable">-y</span> cmake ninja-build gcc-c++ libtool </span><span class="code-line"> </span><span class="code-line"><span class="token function">git</span> clone https://github.com/ttys3/nvim-config.git <span class="token constant environment">$HOME</span>/.config/nvim </span><span class="code-line"><span class="token class-name builtin">cd</span> <span class="token constant environment">$HOME</span>/.config/nvim <span class="token operator">&amp;&amp;</span> <span class="token function">make</span> nvim </span></code></pre></div><p>安装 golang</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token parameter variable">-y</span> golang-bin </span></code></pre></div><p>安装 rust (ref <a href="https://www.rust-lang.org/tools/install">https://www.rust-lang.org/tools/install</a>)</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">curl</span> <span class="token parameter variable">--proto</span> <span class="token string">&#x27;=https&#x27;</span> <span class="token parameter variable">--tlsv1.2</span> <span class="token parameter variable">-sSf</span> https://sh.rustup.rs <span class="token operator">|</span> <span class="token function">sh</span> </span></code></pre></div><p>安装完成后, <code>~/.zshrc</code> 加上:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token keyword module">export</span> <span class="token constant">RUSTUP_DIST_SERVER</span><span class="token operator">=</span><span class="token string">&quot;https://rsproxy.cn&quot;</span> </span><span class="code-line"><span class="token keyword module">export</span> <span class="token constant">RUSTUP_UPDATE_ROOT</span><span class="token operator">=</span><span class="token string">&quot;https://rsproxy.cn/rustup&quot;</span> </span><span class="code-line">source $<span class="token constant">HOME</span><span class="token operator">/</span><span class="token punctuation">.</span><span class="token property-access">cargo</span><span class="token operator">/</span>env </span></code></pre></div><p>去 <a href="https://www.nerdfonts.com/font-downloads">https://www.nerdfonts.com/font-downloads</a> 下载 nerdfont 并安装:</p><p>老灯主要下载了 Iosevka 和 JetBrainsMono</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">mkdir <span class="token operator">-</span>p <span class="token operator">~</span><span class="token operator">/</span><span class="token punctuation">.</span><span class="token property-access">local</span><span class="token operator">/</span>share<span class="token operator">/</span>fonts </span><span class="code-line">cp <span class="token operator">-</span>r <span class="token maybe-class-name">JetBrainsMono</span> <span class="token operator">~</span><span class="token operator">/</span><span class="token punctuation">.</span><span class="token property-access">local</span><span class="token operator">/</span>share<span class="token operator">/</span>fonts<span class="token operator">/</span> </span><span class="code-line">cp <span class="token operator">-</span>r <span class="token maybe-class-name">IosevkaNerd</span> <span class="token operator">~</span><span class="token operator">/</span><span class="token punctuation">.</span><span class="token property-access">local</span><span class="token operator">/</span>share<span class="token operator">/</span>fonts<span class="token operator">/</span> </span></code></pre></div><p>打开 gnome-tweaks 调整默认的 monospace 字体为 JetBrainsMono 或 Iosevka</p><p>grub配置更新:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> grub2-mkconfig <span class="token parameter variable">-o</span> /etc/grub2-efi.cfg </span></code></pre></div><p>这里有点问题, 默认 Fedora 的 grub 扫到了我的 Arch grub 配置, 但是添加的条目有问题:</p><p>Arch 正确的menu是:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">### <span class="token constant">BEGIN</span> <span class="token operator">/</span>etc<span class="token operator">/</span>grub<span class="token punctuation">.</span><span class="token property-access">d</span><span class="token operator">/</span>10_linux ### </span><span class="code-line">menuentry <span class="token string">&#x27;Arch Linux&#x27;</span> <span class="token operator">--</span><span class="token keyword">class</span> <span class="token class-name">arch</span> <span class="token operator">--</span><span class="token keyword">class</span> <span class="token class-name">gnu</span><span class="token operator">-</span>linux <span class="token operator">--</span><span class="token keyword">class</span> <span class="token class-name">gnu</span> <span class="token operator">--</span><span class="token keyword">class</span> <span class="token class-name">os</span> $menuentry_id_option <span class="token string">&#x27;gnulinux-simple-dc941692-cb41-44bc-9bf0-f045fc1fd9f8&#x27;</span> <span class="token punctuation">{</span> </span><span class="code-line"> load_video </span><span class="code-line"> <span class="token keyword">set</span> gfxpayload<span class="token operator">=</span>keep </span><span class="code-line"> insmod gzio </span><span class="code-line"> insmod part_gpt </span><span class="code-line"> insmod ext2 </span><span class="code-line"> search <span class="token operator">--</span>no<span class="token operator">-</span>floppy <span class="token operator">--</span>fs<span class="token operator">-</span>uuid <span class="token operator">--</span>set<span class="token operator">=</span>root a79b862f<span class="token operator">-</span>1a07<span class="token operator">-</span>413f<span class="token operator">-</span><span class="token number">9537</span><span class="token operator">-</span>3922300b3436 </span><span class="code-line"> echo <span class="token string">&#x27;Loading Linux linux ...&#x27;</span> </span><span class="code-line"> linux <span class="token operator">/</span>vmlinuz<span class="token operator">-</span>linux root<span class="token operator">=</span><span class="token operator">/</span>dev<span class="token operator">/</span>mapper<span class="token operator">/</span>vgarch<span class="token operator">-</span>lvroot rw loglevel<span class="token operator">=</span><span class="token number">3</span> noquiet nvidia<span class="token operator">-</span>drm<span class="token punctuation">.</span><span class="token property-access">modeset</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"> echo <span class="token string">&#x27;Loading initial ramdisk ...&#x27;</span> </span><span class="code-line"> initrd <span class="token operator">/</span>intel<span class="token operator">-</span>ucode<span class="token punctuation">.</span><span class="token property-access">img</span> <span class="token operator">/</span>initramfs<span class="token operator">-</span>linux<span class="token punctuation">.</span><span class="token property-access">img</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>Fedora 生成的 arch 启动menu 是这样的:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">### <span class="token constant">BEGIN</span> <span class="token operator">/</span>etc<span class="token operator">/</span>grub<span class="token punctuation">.</span><span class="token property-access">d</span><span class="token operator">/</span>30_os<span class="token operator">-</span>prober ### </span><span class="code-line"> menuentry <span class="token string">&#x27;Arch Linux (on /dev/mapper/vgarch-lvroot)&#x27;</span> <span class="token operator">--</span><span class="token keyword">class</span> <span class="token class-name">gnu</span><span class="token operator">-</span>linux <span class="token operator">--</span><span class="token keyword">class</span> <span class="token class-name">gnu</span> <span class="token operator">--</span><span class="token keyword">class</span> <span class="token class-name">os</span> $menuentry_id_option <span class="token string">&#x27;osprober-gnulinux-/vmlinuz-linux--dc941692-cb41-44bc-9bf0-f045fc1fd9f8&#x27;</span> <span class="token punctuation">{</span> </span><span class="code-line"> insmod part_gpt </span><span class="code-line"> insmod ext2 </span><span class="code-line"> search <span class="token operator">--</span>no<span class="token operator">-</span>floppy <span class="token operator">--</span>fs<span class="token operator">-</span>uuid <span class="token operator">--</span>set<span class="token operator">=</span>root a79b862f<span class="token operator">-</span>1a07<span class="token operator">-</span>413f<span class="token operator">-</span><span class="token number">9537</span><span class="token operator">-</span>3922300b3436 </span><span class="code-line"> linux <span class="token operator">/</span>vmlinuz<span class="token operator">-</span>linux root<span class="token operator">=</span><span class="token operator">/</span>dev<span class="token operator">/</span>mapper<span class="token operator">/</span>vgarch<span class="token operator">-</span>lvroot rw loglevel<span class="token operator">=</span><span class="token number">3</span> noquiet nvidia<span class="token operator">-</span>drm<span class="token punctuation">.</span><span class="token property-access">modeset</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"> initrd <span class="token operator">/</span>intel<span class="token operator">-</span>ucode<span class="token punctuation">.</span><span class="token property-access">img</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>没错, 最后那一行 <code>initrd /intel-ucode.img</code> 错了. 正确的应该是 <code>initrd /intel-ucode.img /initramfs-linux.img</code></p><p>其它Wayland 相关配置请参考 <a href="/post/upgrade-to-gnome-42-and-switch-to-wayland/">/post/upgrade-to-gnome-42-and-switch-to-wayland/</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://fedoraproject.org/wiki/Changes/BtrfsByDefault">https://fedoraproject.org/wiki/Changes/BtrfsByDefault</a></p><p><a href="https://fedoraproject.org/wiki/GRUB_2">https://fedoraproject.org/wiki/GRUB_2</a></p><p><a href="https://github.com/neovim/neovim/wiki/Building-Neovim#building">https://github.com/neovim/neovim/wiki/Building-Neovim#building</a></p><p><a href="https://ask.fedoraproject.org/t/java-cant-find-library/10128">https://ask.fedoraproject.org/t/java-cant-find-library/10128</a></p> Mon, 18 Apr 2022 14:25:30 GMT ttyS3 Fedoraf36Linux https://ttys3.dev/blog/config-mpv-a-better-player Config mpv as a Better Player https://ttys3.dev/blog/config-mpv-a-better-player <h2 id="缘由"><a href="#缘由" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h2><p>产生这篇文章的原因是, 最近老灯从 X11 切 Wayland 了, 而 SMPlayer 又不工作了.</p><p>GNOME 官方的 Video 播放器也能凑合用. 但是老灯还是习惯 mpv 系列.</p><p>但是直接用 mpv 感觉还是不太习惯, 比如外挂字幕选择加载 mpv 貌似没有快捷键, 播放列表管理功能貌似也没有.</p><p>很快在 Github 上面找到一个神级脚本: <a href="https://github.com/darsain/uosc">https://github.com/darsain/uosc</a></p><p>还有一个堪称播放器级别的配置: <a href="https://github.com/thisisshihan/mpv-player-config-snad">https://github.com/thisisshihan/mpv-player-config-snad</a></p><h2 id="mpv-配置目录"><a href="#mpv-配置目录" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>mpv 配置目录</h2><p>首先, 老灯机器上面甚至没有一个 mpv 的配置.</p><p>所以, <a href="https://mpv.io/manual/master/#files">先找文档看看</a>配置文件在哪?</p><p>在 Arch 上, mpv 系统全局配置目录在 <code>/etc/mpv/</code></p><p>老灯看了下, 这个目录下面只有一个 <code>encoding-profiles.conf</code>文件</p><p>然后, 一般情况下, 标准的用户配置目录在 <code>~/.config/mpv</code> , 当然还有一些特例, 比如:</p><blockquote><p>The standard configuration directory. This can be overridden by environment variables, in ascending order:</p><p>1: If <code>$XDG_CONFIG_HOME</code> is set, then the derived configuration directory will be <code>$XDG_CONFIG_HOME/mpv</code>. 2: If <code>$MPV_HOME</code> is set, then the derived configuration directory will be <code>$MPV_HOME</code>.</p><p>If this directory, nor the original configuration directory (see below) do not exist, mpv tries to create this directory automatically.</p></blockquote><p>主要用户配置文件: <code>~/.config/mpv/mpv.conf</code></p><p>主要的 key bindings 配置: <code>~/.config/mpv/input.conf</code></p><p>字体配置: <code>~/.config/mpv/fonts.conf</code></p><blockquote><p>Fontconfig fonts.conf that is customized for mpv. You should include system fonts.conf in this file or mpv would not know about fonts that you already have in the system.</p><p>Only available when libass is built with fontconfig.</p></blockquote><p>字体目录: <code>~/.config/mpv/fonts/</code></p><blockquote><p>Font files in this directory are used by mpv/libass for subtitles. <strong>Useful if you do not want to install fonts to your system.</strong> Note that files in this directory are <strong>loaded into memory</strong> before being used by mpv. If you have a lot of fonts, consider using fonts.conf (see above) to include additional fonts, which is more memory-efficient.</p></blockquote><p>脚本目录: <code>~/.config/mpv/scripts/</code></p><p>osc配置: <code>~/.config/mpv/script-opts/osc.conf</code></p><p>This is loaded by the OSC script. See the <a href="https://mpv.io/manual/master/#on-screen-controller">ON SCREEN CONTROLLER</a> docs for details.</p><p>Other files in this directory are specific to the corresponding scripts as well, and the mpv core doesn&#x27;t touch them.</p><h2 id="uosc-安装"><a href="#uosc-安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>uosc 安装</h2><p>安装后的目录结构:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"> ~/.config/mpv </span><span class="code-line">❯ tree </span><span class="code-line"><span class="token builtin class-name">.</span> </span><span class="code-line">├── input.conf </span><span class="code-line">├── mpv.conf </span><span class="code-line">├── script-opts </span><span class="code-line">│ └── uosc.conf </span><span class="code-line">└── scripts </span><span class="code-line"> └── uosc.lua </span><span class="code-line"> </span><span class="code-line"><span class="token number">2</span> directories, <span class="token number">4</span> files </span></code></pre></div><blockquote><p><strong>uosc</strong> is a replacement for the built in osc, so that has to be disabled first.</p></blockquote><p>由于 uosc 实际上是内置 osc 功能的替代品, 因此内置的必须先禁用掉:</p><p>编辑 <code>~/.config/mpv/mpv.conf</code> 加上:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment"># required so that the 2 UIs don&#x27;t fight each other</span> </span><span class="code-line"><span class="token attr-name key">osc</span><span class="token punctuation">=</span><span class="token attr-value value">no</span> </span><span class="code-line"><span class="token comment"># uosc provides its own seeking/volume indicators, so you also don&#x27;t need this</span> </span><span class="code-line"><span class="token attr-name key">osd-bar</span><span class="token punctuation">=</span><span class="token attr-value value">no</span> </span><span class="code-line"><span class="token comment"># uosc will draw its own window controls if you disable window border</span> </span><span class="code-line"><span class="token attr-name key">border</span><span class="token punctuation">=</span><span class="token attr-value value">no</span> </span></code></pre></div><h3 id="下载脚本和脚本配置"><a href="#下载脚本和脚本配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>下载脚本和脚本配置</h3><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">curl</span> <span class="token parameter variable">-sSf</span> --create-dirs <span class="token parameter variable">-o</span> <span class="token constant environment">$HOME</span>/.config/mpv/scripts/uosc.lua <span class="token punctuation">\</span> </span><span class="code-line">https://raw.githubusercontent.com/darsain/uosc/master/uosc.lua </span><span class="code-line"> </span><span class="code-line"><span class="token function">curl</span> <span class="token parameter variable">-sSf</span> --create-dirs <span class="token parameter variable">-o</span> <span class="token constant environment">$HOME</span>/.config/mpv/script-opts/uosc.conf <span class="token punctuation">\</span> </span><span class="code-line">https://raw.githubusercontent.com/darsain/uosc/master/uosc.conf </span></code></pre></div><h3 id="keybindings-配置"><a href="#keybindings-配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Keybindings 配置</h3><p>编辑 <code>~/.config/mpv/input.conf</code> 加上:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">menu script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>menu </span><span class="code-line">mbtn_right script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>menu </span><span class="code-line">o script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>open<span class="token operator">-</span>file #<span class="token operator">!</span> <span class="token maybe-class-name">Open</span> file </span><span class="code-line">alt<span class="token operator">+</span>s script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>load<span class="token operator">-</span>subtitles #<span class="token operator">!</span> <span class="token maybe-class-name">Load</span> subtitles </span><span class="code-line"><span class="token constant">S</span> script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>subtitles #<span class="token operator">!</span> <span class="token maybe-class-name">Select</span> subtitles </span><span class="code-line"><span class="token constant">A</span> script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>audio #<span class="token operator">!</span> <span class="token maybe-class-name">Select</span> audio </span><span class="code-line">ctrl<span class="token operator">+</span>s <span class="token keyword">async</span> screenshot #<span class="token operator">!</span> <span class="token maybe-class-name">Utils</span> <span class="token operator">&gt;</span> <span class="token maybe-class-name">Screenshot</span> </span><span class="code-line"><span class="token constant">P</span> script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>playlist #<span class="token operator">!</span> <span class="token maybe-class-name">Utils</span> <span class="token operator">&gt;</span> <span class="token maybe-class-name">Playlist</span> </span><span class="code-line"><span class="token constant">C</span> script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>chapters #<span class="token operator">!</span> <span class="token maybe-class-name">Utils</span> <span class="token operator">&gt;</span> <span class="token maybe-class-name">Chapters</span> </span><span class="code-line"># script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>open<span class="token operator">-</span>config<span class="token operator">-</span>directory #<span class="token operator">!</span> <span class="token maybe-class-name">Utils</span> <span class="token operator">&gt;</span> <span class="token maybe-class-name">Open</span> config directory </span><span class="code-line"># <span class="token keyword">set</span> video<span class="token operator">-</span>aspect<span class="token operator">-</span>override <span class="token string">&quot;-1&quot;</span> #<span class="token operator">!</span> <span class="token maybe-class-name">Aspect</span> ratio <span class="token operator">&gt;</span> <span class="token maybe-class-name">Default</span> </span><span class="code-line"># <span class="token keyword">set</span> video<span class="token operator">-</span>aspect<span class="token operator">-</span>override <span class="token string">&quot;16:9&quot;</span> #<span class="token operator">!</span> <span class="token maybe-class-name">Aspect</span> ratio <span class="token operator">&gt;</span> <span class="token number">16</span><span class="token operator">:</span><span class="token number">9</span> </span><span class="code-line"># <span class="token keyword">set</span> video<span class="token operator">-</span>aspect<span class="token operator">-</span>override <span class="token string">&quot;4:3&quot;</span> #<span class="token operator">!</span> <span class="token maybe-class-name">Aspect</span> ratio <span class="token operator">&gt;</span> <span class="token number">4</span><span class="token operator">:</span><span class="token number">3</span> </span><span class="code-line"># <span class="token keyword">set</span> video<span class="token operator">-</span>aspect<span class="token operator">-</span>override <span class="token string">&quot;2.35:1&quot;</span> #<span class="token operator">!</span> <span class="token maybe-class-name">Aspect</span> ratio <span class="token operator">&gt;</span> <span class="token number">2.35</span><span class="token operator">:</span><span class="token number">1</span> </span><span class="code-line"><span class="token constant">O</span> script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>show<span class="token operator">-</span><span class="token keyword">in</span><span class="token operator">-</span>directory #<span class="token operator">!</span> <span class="token maybe-class-name">Show</span> <span class="token keyword">in</span> directory </span><span class="code-line">esc quit #<span class="token operator">!</span> <span class="token maybe-class-name">Quit</span> </span><span class="code-line">q quit #<span class="token operator">!</span> </span></code></pre></div><p>这个键绑定老灯稍做了修改:</p><p>主要改动为:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">ctrl<span class="token operator">+</span>o script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>open<span class="token operator">-</span>file #<span class="token operator">!</span> <span class="token maybe-class-name">Open</span> file </span><span class="code-line">alt<span class="token operator">+</span>o script<span class="token operator">-</span>binding uosc<span class="token operator">/</span>show<span class="token operator">-</span><span class="token keyword">in</span><span class="token operator">-</span>directory #<span class="token operator">!</span> <span class="token maybe-class-name">Show</span> <span class="token keyword">in</span> directory </span></code></pre></div><p>打开文件这两个操作老灯认为没有显示 osd 频繁, 因此 o 留给 osd toggle.</p><h2 id="效果展示"><a href="#效果展示" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>效果展示</h2><p>选择视频文件打开:</p><div><img alt="" src="https://ttys3.dev/static/assets/file-select-2022-04-09_19-53-R7CVFUIT.png" width="1961" height="1155"/></div><p>内置字幕选择(支持方向键 和 vim hjkl 或 游戏党的 wasd):</p><div><img alt="" src="https://ttys3.dev/static/assets/subtitle-selector-2022-04-09-19-52-24-YHVGQ4AW.png" width="2086" height="1202"/></div><p>utils 功能:</p><div><img alt="" src="https://ttys3.dev/static/assets/utils-sub-menu-2022-04-09-19-54-04-3J5QZKQR.png" width="1955" height="1113"/></div><p>播放列表功能 (相应的快捷键见 <a href="https://github.com/ttys3/my-mpv-config/blob/main/input.conf">input.conf </a>):</p><div><img alt="" src="https://ttys3.dev/static/assets/playlist-2022-04-09_22-25-ARV3W4D7.png" width="1925" height="923"/></div><h2 id="其它-mpv-内置快捷键"><a href="#其它-mpv-内置快捷键" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它 mpv 内置快捷键</h2><p><strong>F8</strong> Show the playlist and the current position in it (useful only if a UI window is used, broken on the terminal).</p><p><strong>F9</strong> Show the list of audio and subtitle streams (useful only if a UI window is used, broken on the terminal).</p><p><strong>i and I</strong> Show/toggle an overlay displaying statistics about the currently playing file such as codec, framerate, number of dropped frames and so on. See STATS for more information.</p><p><strong>del</strong> Cycle OSC visibility between never / auto (mouse-move) / always</p><p><strong>`</strong> Show the console. (ESC closes it again. See CONSOLE.)</p><p><strong>o (also P)</strong> Show progression bar, elapsed time and total duration on the OSD.</p><p><strong>O</strong> Toggle OSD states between normal and playback time/duration.</p><p><strong>v</strong> Toggle subtitle visibility.</p><p><strong>j and J</strong> Cycle through the available subtitles.</p><p><strong>z and Z</strong> Adjust subtitle delay by +/- 0.1 seconds. The x key does the same as Z currently, but use is discouraged.</p><p><strong>9 and 0</strong> Decrease/increase volume.</p><p><strong>m</strong> Mute sound.</p><p><strong><code>_</code></strong> Cycle through the available video tracks.</p><p><strong><code>#</code></strong></p><p>Cycle through the available audio tracks.</p><p><code>f</code> Toggle fullscreen (see also --fs).</p><p><code>ESC</code> Exit fullscreen mode.</p><p><code>T</code> Toggle stay-on-top (see also --ontop).</p><p>最后, 老灯折腾完的配置在这: <a href="https://github.com/ttys3/my-mpv-config">https://github.com/ttys3/my-mpv-config</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://github.com/darsain/uosc">https://github.com/darsain/uosc</a></p><p><a href="https://mpv.io/manual/master/#files">https://mpv.io/manual/master/#files</a></p><p><a href="https://mpv.io/manual/master/#configuration-files">https://mpv.io/manual/master/#configuration-files</a></p><p><a href="https://mpv.io/manual/master/#input-conf">https://mpv.io/manual/master/#input-conf</a></p><p><a href="https://github.com/mpv-player/mpv/blob/master/etc/input.conf">https://github.com/mpv-player/mpv/blob/master/etc/input.conf</a></p><p><a href="https://iamscum.wordpress.com/guides/videoplayback-guide/mpv-conf/">https://iamscum.wordpress.com/guides/videoplayback-guide/mpv-conf/</a></p><p><a href="https://github.com/thisisshihan/mpv-player-config-snad">https://github.com/thisisshihan/mpv-player-config-snad</a></p><p>其它资源:</p><p>资源获取:</p><p><a href="https://github.com/mpv-player/mpv/wiki/User-Scripts">https://github.com/mpv-player/mpv/wiki/User-Scripts</a></p><p><a href="https://github.com/topics/mpv-script?o=desc&amp;s=stars">https://github.com/topics/mpv-script?o=desc&amp;s=stars</a></p><p><a href="https://github.com/topics/mpv-config">https://github.com/topics/mpv-config</a></p><p>老灯看到觉得不错的:</p><p>windows <a href="https://github.com/422658476/MPV-EASY-Player">https://github.com/422658476/MPV-EASY-Player</a></p><p>windows <a href="https://github.com/hooke007/MPV_lazy">https://github.com/hooke007/MPV_lazy</a></p><p><a href="https://github.com/jonniek/mpv-playlistmanager">https://github.com/jonniek/mpv-playlistmanager</a></p><p><a href="https://github.com/CogentRedTester/mpv-file-browser">https://github.com/CogentRedTester/mpv-file-browser</a></p><p><a href="https://github.com/maoiscat/mpv-osc-morden">https://github.com/maoiscat/mpv-osc-morden</a></p><p><a href="https://github.com/hl2guide/better-mpv-config/blob/master/mpv.conf">https://github.com/hl2guide/better-mpv-config/blob/master/mpv.conf</a></p> Sat, 09 Apr 2022 12:15:06 GMT ttyS3 https://ttys3.dev/blog/upgrade-to-gnome-42-and-switch-to-wayland Upgrade to GNOME 42 and Switch To Wayland (updated) https://ttys3.dev/blog/upgrade-to-gnome-42-and-switch-to-wayland <blockquote><p>我能说我这么多年用 N 卡一直是在跑 X11 么?</p><p>今天终于能换 Wayland 了</p></blockquote><p>OS: Arch Linux x86_64</p><p>Kernel: 5.17.1-arch1-1</p><p>Card: GeForce GTX 1060</p><p>Resolution: 3840x2160</p><p>DE: GNOME 42.0</p><p>WM: Mutter</p><h2 id="背景"><a href="#背景" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>背景</h2><p>Wayland 的支持看上去已经较为完善了.</p><p>比如近期 Ubuntu 和 Fedora 都会在 4 月份发布的新版本中默认对于 Nvidia 510版本以上的驱动 使用 Wayland:</p><p><a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=Ubuntu-22.04-NV-Wayland-Default">Ubuntu 22.04 LTS Will Default To Wayland With NVIDIA For v510+ Driver</a></p><p><a href="https://fedoraproject.org/wiki/Changes/WaylandByDefaultOnNVIDIA">Fedora Linux 36 changed to Wayland By Default with NVIDIA proprietary Driver</a></p><p>注意: 之所以有&quot;Nvidia 510版本以上的驱动&quot;这个限制, 一是因为 510 之前这个驱动对于 Wayland 支持有问题. 二是因为, 对于其它驱动, 其实 Fedora 早在 Fedora 25 就已经是默认 Wayland 了.</p><p>see <a href="https://fedoraproject.org/wiki/Changes/WaylandByDefaultOnNVIDIA#Benefit_to_Fedora">https://fedoraproject.org/wiki/Changes/WaylandByDefaultOnNVIDIA#Benefit_to_Fedora</a></p><blockquote><p>Fedora has changed to Wayland by default since <a href="https://fedoraproject.org/wiki/Changes/Login_Screen_Over_Wayland" title="Changes/Login Screen Over Wayland">Fedora 22</a>, but the NVIDIA proprietary driver has been an exception ever since (either because originally Wayland would be disabled with NVIDIA drivers, or more recently Xorg would be used by default).</p></blockquote><p>另外还有 Fedora 吐槽 NVIDIA 专属驱动: <a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=Fedora-FPL-NVIDIA-Blobs">Fedora Project Leader Calls Out NVIDIA Over Their Proprietary Linux Drivers</a></p><p>我们看下 Arch 上面的进度:</p><p>2个月前: <a href="https://www.reddit.com/r/gnome/comments/sxs24r/gnome_42_beta_on_archlinux/">有第三方构建了 GNOME unstable</a></p><p>10天前: <a href="https://www.reddit.com/r/gnome/comments/ts9c9q/gnome_42_begins_hitting_arch_linux_gnomeunstable/">hitting Arch Linux gnome-unstable repo</a></p><p>5天前: <a href="https://www.reddit.com/r/archlinux/comments/tvtc3n/fyi_gnome_42_just_hit_testing_repo/">GNOME 42 已经进入 Arch testing 仓库了</a></p><p>2天前: <a href="https://www.reddit.com/r/archlinux/comments/txx3d0/gnome_42_is_here_check_out_extra_repo/">Gnome 42 is here! Check out Extra Repo</a></p><p>事实上我是2天之前得知消息的当天就升级到了 GNOME 42, 同时我的机器都是Nvidia显卡的, 因此同时也切换到了 Wayland.</p><p>升级到GNOME 42, 本身没有什么大问题. 主要的问题来自于当前一些应用对于 Wayland 的支持程度(部分需要添加额外的flags), 有一些甚至完全不支持(只能跑在xwayland下面).</p><p>本文主要分享一下踩过的坑及一些解决办法.</p><h2 id="升级操作"><a href="#升级操作" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>升级操作</h2><p>升级本身没有什么特别要注意的. 直接 <code>paru</code> 就好了.</p><h3 id="注意安装-wayland-支持"><a href="#注意安装-wayland-支持" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>注意安装 wayland 支持</h3><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">paru <span class="token variable parameter">-S</span> <span class="token variable parameter">--needed</span> glfw-wayland xorg-xwayland wayland-utils qt6-wayland qt5-wayland </span></code></pre></div><h3 id="锁屏解锁问题"><a href="#锁屏解锁问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>锁屏解锁问题</h3><p>注意升级后去 <a href="https://extensions.gnome.org/local/">https://extensions.gnome.org/local/</a> 升级所有能升级的 extensions.</p><p><a href="https://extensions.gnome.org/extension/2935/control-blur-effect-on-lock-screen/">https://extensions.gnome.org/extension/2935/control-blur-effect-on-lock-screen/</a> 如果安装了这个插件要卸载掉. 会有一定概率导致锁屏后无法登录回原来的会话. 具体的问题是: 锁屏, 然后解锁, 在输入密码框你准备输入密码的时候, GNOME 把所有当前会话启动的进程杀死, 然后 GDM 重启, 退回到登录界面, 这个时候你再进去, 已经跟重启登录没两样了, 进程都被杀死了.</p><p>可以启用 gdm debug 看到更详细的过程, 编辑 <code>/etc/gdm/custom.conf</code> 启用 <code>Enable=true</code>:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">debug</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token comment"># Uncomment the line below to turn on debugging</span> </span><span class="code-line"><span class="token attr-name key">Enable</span><span class="token punctuation">=</span><span class="token attr-value value">true</span> </span></code></pre></div><p>重启 gdm 生效.</p><h3 id="休眠问题"><a href="#休眠问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>休眠问题</h3><p>休眠功能是有问题的. 必须禁用.</p><p>检查一下界面展示的配置 ( Settings - Power ) 和 实际的配置是不是一致:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">❯ gsettings list<span class="token operator">-</span>recursively org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> ambient<span class="token operator">-</span>enabled <span class="token boolean">true</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> idle<span class="token operator">-</span>brightness <span class="token number">30</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> idle<span class="token operator">-</span>dim <span class="token boolean">true</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> power<span class="token operator">-</span>button<span class="token operator">-</span>action <span class="token string">&#x27;nothing&#x27;</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> power<span class="token operator">-</span>saver<span class="token operator">-</span>profile<span class="token operator">-</span>on<span class="token operator">-</span>low<span class="token operator">-</span>battery <span class="token boolean">true</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> sleep<span class="token operator">-</span>inactive<span class="token operator">-</span>ac<span class="token operator">-</span>timeout <span class="token number">7200</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> sleep<span class="token operator">-</span>inactive<span class="token operator">-</span>ac<span class="token operator">-</span>type <span class="token string">&#x27;nothing&#x27;</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> sleep<span class="token operator">-</span>inactive<span class="token operator">-</span>battery<span class="token operator">-</span>timeout <span class="token number">1200</span> </span><span class="code-line">org<span class="token punctuation">.</span><span class="token property-access">gnome</span><span class="token punctuation">.</span><span class="token property-access">settings</span><span class="token operator">-</span>daemon<span class="token punctuation">.</span><span class="token property-access">plugins</span><span class="token punctuation">.</span><span class="token property-access">power</span> sleep<span class="token operator">-</span>inactive<span class="token operator">-</span>battery<span class="token operator">-</span>type <span class="token string">&#x27;suspend&#x27;</span> </span></code></pre></div><p>重点关注 <code>power-button-action &#x27;nothing&#x27;</code> 和 <code>sleep-inactive-ac-type &#x27;nothing&#x27;</code>, 由于我是台式机, 因此不需要关注 <code>sleep-inactive-battery-type</code></p><p>可以通过 systemd 彻底禁用休眠:</p><p>编辑 <code>/etc/systemd/sleep.conf</code> 配置:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Sleep</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">AllowSuspend</span><span class="token punctuation">=</span><span class="token attr-value value">no</span> </span><span class="code-line"><span class="token attr-name key">AllowHibernation</span><span class="token punctuation">=</span><span class="token attr-value value">no</span> </span><span class="code-line"><span class="token attr-name key">AllowSuspendThenHibernate</span><span class="token punctuation">=</span><span class="token attr-value value">no</span> </span></code></pre></div><p>这样以后, 再也不用担心在关机按钮那里误点 Suspend 或 Hibernate 了 (同时休眠相关的选项会从 Settings - Power 界面消失):</p><div><img alt="" src="https://ttys3.dev/static/assets/screenshot-from-2022-04-09-12-25-45-5CLHY3PW.png" width="708" height="618"/></div><p>花屏的图我这里也放一个吧:</p><div><img alt="" src="https://ttys3.dev/static/assets/screenshot-from-2022-04-09-09-38-18-P5MJ7CCJ.png" width="1200" height="906"/></div><h2 id="切换到-wayland"><a href="#切换到-wayland" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>切换到 Wayland</h2><ol><li>确认当前的Nvidia显卡驱动版本已经大于 510</li></ol><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ paru <span class="token variable parameter">-Qi</span> nvidia <span class="token operator">|</span> rg Version </span><span class="code-line">Version <span class="token builtin class-name">:</span> <span class="token number">510.60</span>.02-11 </span></code></pre></div><ol start="2"><li>确认当前N卡驱动模块已经启用 KMS</li></ol><p>KMS 默认是禁用的 <code>(1 = enable, 0 = disable (default))</code> :</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">modinfo nvidia_drm <span class="token operator">|</span> rg mode </span><span class="code-line">depends: nvidia-modeset </span><span class="code-line">parm: modeset:Enable atomic kernel modesetting <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">=</span> enable, <span class="token number">0</span> <span class="token operator">=</span> disable <span class="token punctuation">(</span>default<span class="token punctuation">))</span> <span class="token punctuation">(</span>bool<span class="token punctuation">)</span> </span></code></pre></div><p>我们检查下内核参数: <code>cat /proc/cmdline</code> , 如果没有 <code>nvidia-drm.modeset=1</code> 则要加上.</p><p>编辑 <code>/etc/default/grub</code> 加上即可, 如:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token attr-name key">GRUB_CMDLINE_LINUX_DEFAULT</span><span class="token punctuation">=</span><span class="token attr-value value">&quot;<span class="token inner-value">loglevel=3 noquiet nvidia-drm.modeset=1</span>&quot;</span> </span></code></pre></div><p>然后重新生成一下 grub2 配置:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">grub-mkconfig</span> <span class="token variable parameter">-o</span> /boot/grub/grub.cfg </span></code></pre></div><p>重启后检查 cmdline 确认 OK:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">cat</span> /proc/cmdline </span><span class="code-line"><span class="token variable assign-left">BOOT_IMAGE</span><span class="token operator">=</span>/vmlinuz-linux <span class="token variable assign-left">root</span><span class="token operator">=</span>/dev/mapper/archlinux-root rw <span class="token variable assign-left">loglevel</span><span class="token operator">=</span><span class="token number">3</span> noquiet nvidia-drm.modeset<span class="token operator">=</span><span class="token number">1</span> </span></code></pre></div><p>其实也不用检查 cmdline, 重启后在 GDM 登录界面, 点击用户名, 别急着输入密码, 此时会看到右下角有一个齿轮图标,点击可以发现, 默认的 session 是 GNOME (这个其实就是wayland session), 然后剩下的依次是GNOME Classic, GNOME Classic on Xorg, GNOME on Xorg. 出现这些就表示 GDM 已经检测到 Wayland 支持了.</p><div><img alt="" src="https://ttys3.dev/static/assets/gdm-session-selector-5YPKSGZE.jpg" width="356" height="260"/></div><p>放张图 (使用 GNOME 42 自带的 screenshot 截图的: 右击窗口标题栏, 选择<strong>take screenshot</strong>):</p><div><img alt="" src="https://ttys3.dev/static/assets/screenshot-from-2022-04-09-12-08-25-2EWGBEVN.png" width="2454" height="2154"/></div><p>如果不能切 Wayland 的, 可以尝试强制禁用 gdm udev 规则:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">ln</span> <span class="token variable parameter">-s</span> /dev/null /etc/udev/rules.d/61-gdm.rules </span></code></pre></div><h2 id="troubleshooting"><a href="#troubleshooting" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Troubleshooting</h2><p>没错, 这里到了最麻烦的部分了. 首先我们安装一下 Xorg 的一个小工具 <code>paru -S xorg-xlsclients</code></p><p>这个工具的作用是 &quot;List client applications running on a display&quot;</p><p>因此, 凡是被 xlsclients 识别出是客户端的, 我们就知道这个程序是跑在 X11 兼容模式 (xwayland), 而不是跑在 Wayland 协议下.</p><h3 id="flameshot"><a href="#flameshot" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>flameshot</h3><p>flameshot 当前是基于 qt5 编译的, qt5 当前对于 Wayland 的支持已经较好. 但是由于我之前是 X11 的桌面, 因此这里遇到了麻烦, flameshot 无法截图. 解决办法是安装 xdg-desktop-portal :</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">paru <span class="token variable parameter">-S</span> xdg-desktop-portal xdg-desktop-portal-gnome </span></code></pre></div><p>如果我们观察 flameshot 的 dbus 调用:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">dbus-monitor <span class="token variable parameter">--session</span> <span class="token variable assign-left">sender</span><span class="token operator">=</span>org.flameshot.Flameshot </span></code></pre></div><p>我们会发现它截图的时候实际上是调用的 <code>org.freedesktop.portal.Screenshot</code> 接口 (正是由 <code>xdg-desktop-portal</code> 提供):</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">method call time<span class="token operator">=</span><span class="token number">1649470142.114187</span> sender<span class="token operator">=</span><span class="token operator">:</span><span class="token number">1.281</span> <span class="token operator">-</span><span class="token operator">&gt;</span> destination<span class="token operator">=</span>org<span class="token punctuation">.</span><span class="token property-access">freedesktop</span><span class="token punctuation">.</span><span class="token property-access">portal</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Desktop</span></span> serial<span class="token operator">=</span><span class="token number">27</span> path<span class="token operator">=</span><span class="token operator">/</span>org<span class="token operator">/</span>freedesktop<span class="token operator">/</span>portal<span class="token operator">/</span>desktop<span class="token punctuation">;</span> <span class="token keyword">interface</span><span class="token operator">=</span>org<span class="token punctuation">.</span><span class="token property-access">freedesktop</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">DBus</span></span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Introspectable</span></span><span class="token punctuation">;</span> member<span class="token operator">=</span><span class="token maybe-class-name">Introspect</span> </span><span class="code-line">method call time<span class="token operator">=</span><span class="token number">1649470142.114449</span> sender<span class="token operator">=</span><span class="token operator">:</span><span class="token number">1.281</span> <span class="token operator">-</span><span class="token operator">&gt;</span> destination<span class="token operator">=</span>org<span class="token punctuation">.</span><span class="token property-access">freedesktop</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">DBus</span></span> serial<span class="token operator">=</span><span class="token number">28</span> path<span class="token operator">=</span><span class="token operator">/</span>org<span class="token operator">/</span>freedesktop<span class="token operator">/</span><span class="token maybe-class-name">DBus</span><span class="token punctuation">;</span> <span class="token keyword">interface</span><span class="token operator">=</span>org<span class="token punctuation">.</span><span class="token property-access">freedesktop</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">DBus</span></span><span class="token punctuation">;</span> member<span class="token operator">=</span><span class="token maybe-class-name">AddMatch</span> </span><span class="code-line"> string <span class="token string">&quot;type=&#x27;signal&#x27;,sender=&#x27;org.freedesktop.portal.Desktop&#x27;,path=&#x27;/org/freedesktop/portal/desktop/request/1_281/90f9e60a9e1f4e1bb80ec889f15e855f&#x27;,interface=&#x27;org.freedesktop.portal.Request&#x27;,member=&#x27;Response&#x27;&quot;</span> </span><span class="code-line">method call time<span class="token operator">=</span><span class="token number">1649470142.114597</span> sender<span class="token operator">=</span><span class="token operator">:</span><span class="token number">1.281</span> <span class="token operator">-</span><span class="token operator">&gt;</span> destination<span class="token operator">=</span>org<span class="token punctuation">.</span><span class="token property-access">freedesktop</span><span class="token punctuation">.</span><span class="token property-access">portal</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Desktop</span></span> serial<span class="token operator">=</span><span class="token number">29</span> path<span class="token operator">=</span><span class="token operator">/</span>org<span class="token operator">/</span>freedesktop<span class="token operator">/</span>portal<span class="token operator">/</span>desktop<span class="token punctuation">;</span> <span class="token keyword">interface</span><span class="token operator">=</span>org<span class="token punctuation">.</span><span class="token property-access">freedesktop</span><span class="token punctuation">.</span><span class="token property-access">portal</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Screenshot</span></span><span class="token punctuation">;</span> member<span class="token operator">=</span><span class="token maybe-class-name">Screenshot</span> </span><span class="code-line"> string <span class="token string">&quot;&quot;</span> </span><span class="code-line"> array \<span class="token punctuation">[</span> </span><span class="code-line"> dict <span class="token function">entry</span><span class="token punctuation">(</span> </span><span class="code-line"> string <span class="token string">&quot;handle_token&quot;</span> </span><span class="code-line"> variant string <span class="token string">&quot;90f9e60a9e1f4e1bb80ec889f15e855f&quot;</span> </span><span class="code-line"> <span class="token punctuation">)</span> </span><span class="code-line"> dict <span class="token function">entry</span><span class="token punctuation">(</span> </span><span class="code-line"> string <span class="token string">&quot;interactive&quot;</span> </span><span class="code-line"> variant boolean <span class="token boolean">false</span> </span><span class="code-line"> <span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span></code></pre></div><p>另一方面是, 其实 flameshot 包的依赖里面已经说明了这一点, 但是由于我新非新装, 因此不会太容易看到这个提示:</p><p>xdg-desktop-portal: for wayland support, you will need the implementation for your wayland desktop environment</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">Optional Deps <span class="token builtin class-name">:</span> gnome-shell-extension-appindicator: <span class="token keyword">for</span> system tray icon </span><span class="code-line"> <span class="token keyword">if</span> you are using Gnome </span><span class="code-line"> grim: <span class="token keyword">for</span> wlroots wayland support </span><span class="code-line"> xdg-desktop-portal: <span class="token keyword">for</span> wayland support, you will need </span><span class="code-line"> the implementation <span class="token keyword">for</span> your wayland desktop environment </span><span class="code-line"> <span class="token punctuation">[</span>installed<span class="token punctuation">]</span> </span><span class="code-line">Required By <span class="token builtin class-name">:</span> None </span><span class="code-line">Optional For <span class="token builtin class-name">:</span> None </span><span class="code-line">Conflicts With <span class="token builtin class-name">:</span> None </span></code></pre></div><p>在 Arch 文档有提到另外一点, 不过我貌似没有遇到这个问题:</p><blockquote><p><strong>Flameshot does not use currently visible windows</strong> You may encounter this issue if you have installed xf86-video-intel.</p><p>Simply remove the <code>xf86-video-intel</code> package and make sure there is no dangling X11 configuration for the package under <code>/etc/X11/xorg.conf.d/</code>.</p><p>Then reboot the system.</p><p>This was discussed in an issue on the Flameshot Github repository: <a href="https://github.com/flameshot-org/flameshot/issues/1677">https://github.com/flameshot-org/flameshot/issues/1677</a>.</p></blockquote><p>好了, 截图的功能能用了, 但是还有另外一个蛋疼的问题: &quot;to take screenshot I need to click &quot;Share&quot; EVERY time&quot;</p><p>即每次 flameshot 截屏, 会弹出一个 xdg portal 的界面, 你要点击这个 &quot;Share&quot; 按钮, 才会继续进入 flameshot 的截图和标注界面. (实际上是把整个屏幕先完全截取, 保存在 ~/Pictures/Screenshot.png 文件, 然后 flameshot 应该是拿这个文件在操作. 如果此时不在 flameshot 做接下来的操作, 那么这个文件会残留在这个位置, 否则, 这个中间文件会被删除)</p><div><img alt="" src="https://ttys3.dev/static/assets/screenshot-via-portal-2022-04-09-13-12-33-TR6PXJCT.jpg" width="1508" height="1080"/></div><p>flameshot 有人提出了这个问题: <a href="https://github.com/flameshot-org/flameshot/issues/2186">https://github.com/flameshot-org/flameshot/issues/2186</a></p><p>但是其实这个问题, flameshot 这边无能为力. xdg-desktop-portal 需要改进.</p><p>另外提一下, GNOME 自带的 <code>gnome-screenshot</code> 似乎有&quot;特权&quot;, 可以不需要通过 xdg-desktop-portal 来截屏. 但是 flameshot 无法调用这种 private 接口.</p><h3 id="slack"><a href="#slack" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Slack</h3><p>Slack 当前只能跑在 XWayland 模式. 由于它用的 electron 版本太老了. 像下面这样添加 <code>--enable-features=UseOzonePlatform --ozone-platform=wayland</code> 参数是无法成功启动的:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">env</span> <span class="token variable assign-left">LIBVA_DRIVER_NAME</span><span class="token operator">=</span><span class="token string">&quot;&quot;</span> /usr/bin/slack <span class="token variable parameter">-s</span> --enable-features<span class="token operator">=</span>UseOzonePlatform --ozone-platform<span class="token operator">=</span>wayland </span></code></pre></div><p>XWayland 模式下的 Slack 有什么问题? 嗯, 问题就是, 输入中文的时候会卡顿. 这一点似乎在所有基于 electron 的 Linux 应用上面都有所表现. 比如 vs code 也有这个问题.</p><p>有个 aur 包, <a href="https://aur.archlinux.org/packages/slack-electron">slack-electron</a> , 测试了下貌似对于解决中文输入问题没有什么帮助.</p><p>结论: 先 XWayland 将就着用着吧, 或者直接使用 slack web 版.</p><p>2022-04-13 更新: 受到这个评论 <a href="https://github.com/swaywm/sway/issues/2508#issuecomment-438185459">https://github.com/swaywm/sway/issues/2508#issuecomment-438185459</a> 的启发:</p><blockquote><p>on slack the freezing seems to get better when you disable (or enable) hardware acceleration.</p></blockquote><p>老灯发现 禁用 HwAcceleration 后, 打字什么的都流畅多了, 界面也不卡顿了.</p><p>可以直接在 Slack prefs 配置的高级选项里禁用hw acc, 或者, 直接修改配置文件 <code>~/.config/Slack/local-settings.json</code> 增加:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token property string-property">&quot;useHwAcceleration&quot;</span><span class="token operator">:</span><span class="token boolean">false</span> </span></code></pre></div><h3 id="discord"><a href="#discord" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Discord</h3><p>Discord 同样是跑在 XWayland 下, 但是我测试的时候发现, 一定要设置 <code>LIBVA_DRIVER_NAME</code> (猜测跟我安装了 libva Intel 硬件加速相关库有关)</p><p>当前 Intel 12 代 CPU 集显的硬件加速在 Linux 下面还不支持. 因此我这里用的是 <code>vdpau</code> driver.</p><p><code>env LIBVA_DRIVER_NAME=vdpau /usr/bin/discord</code> 可以成功启动. 我们需要覆盖一下 <code>discord.desktop</code> 文件:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">cp</span> <span class="token variable parameter">-v</span> /usr/share/applications/discord.desktop ~/.local/share/applications/ </span><span class="code-line"><span class="token function">sed</span> <span class="token variable parameter">-i</span> <span class="token string">&#x27;s|Exec=/usr/bin/discord|Exec=env LIBVA_DRIVER_NAME=vdpau /usr/bin/discord|g&#x27;</span> ~/.local/share/applications/discord.desktop </span></code></pre></div><h3 id="chrome-chromium-和-microsoft-edge"><a href="#chrome-chromium-和-microsoft-edge" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Chrome, Chromium 和 Microsoft Edge</h3><p>Chrome, Chromium 和 Microsoft Edge 可以跑在原生 Wayland 下面, 只是需要添加 flags.</p><p>对于 Chromium , 编辑 <code>~/.config/chromium-flags.conf</code> 增加:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token operator">--</span>enable<span class="token operator">-</span>features<span class="token operator">=</span><span class="token maybe-class-name">UseOzonePlatform</span> </span><span class="code-line"><span class="token operator">--</span>ozone<span class="token operator">-</span>platform<span class="token operator">=</span>wayland </span><span class="code-line"><span class="token operator">--</span>gtk<span class="token operator">-</span>version<span class="token operator">=</span><span class="token number">4</span> </span></code></pre></div><p>对于 Chrome, 这个文件是 <code>~/.config/chrome-flags.conf</code>, 对于 Microsoft Edge, 这个文件是 <code>~/.config/microsoft-edge-stable-flags.conf</code></p><p>注意这里老灯还多添加了一个 <code>--gtk-version=4</code>, 这个主要是为了修复 <a href="https://github.com/fcitx/fcitx5/issues/263">Wayland 下面的输入法支持问题</a>, 要不然无法输入中文.</p><p>另外提一句, 你怎么知道这个文件的位置的? 除了看文档, 更靠谱的是, 通过其启动shell脚本判断:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">❯ rg <span class="token string">&#x27;flags.conf&#x27;</span> <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>microsoft<span class="token operator">-</span>edge<span class="token operator">-</span>stable </span><span class="code-line"><span class="token number">2</span><span class="token operator">:</span># <span class="token maybe-class-name">Launches</span> <span class="token constant">MS</span> <span class="token maybe-class-name">Edge</span> <span class="token keyword">with</span> flags specified <span class="token keyword">in</span> $<span class="token constant">XDG_CONFIG_HOME</span><span class="token operator">/</span>microsoft<span class="token operator">-</span>edge<span class="token operator">-</span>beta<span class="token operator">-</span>flags<span class="token punctuation">.</span><span class="token property-access">conf</span> </span><span class="code-line"><span class="token number">11</span><span class="token operator">:</span><span class="token keyword control-flow">if</span> <span class="token punctuation">[</span> <span class="token operator">-</span>r <span class="token string">&quot;${XDG_CONFIG_HOME}/microsoft-edge-stable-flags.conf&quot;</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> then </span><span class="code-line"><span class="token number">12</span><span class="token operator">:</span> <span class="token constant">EDGE_USER_FLAGS</span><span class="token operator">=</span><span class="token string">&quot;$(cat &quot;</span>$<span class="token constant">XDG_CONFIG_HOME</span><span class="token operator">/</span>microsoft<span class="token operator">-</span>edge<span class="token operator">-</span>stable<span class="token operator">-</span>flags<span class="token punctuation">.</span><span class="token property-access">conf</span><span class="token string">&quot;)&quot;</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">❯ rg <span class="token string">&#x27;flags.conf&#x27;</span> <span class="token operator">/</span>usr<span class="token operator">/</span>bin<span class="token operator">/</span>google<span class="token operator">-</span>chrome<span class="token operator">-</span>stable </span><span class="code-line"><span class="token number">6</span><span class="token operator">:</span><span class="token keyword control-flow">if</span> <span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token operator">-</span>f $<span class="token constant">XDG_CONFIG_HOME</span><span class="token operator">/</span>chrome<span class="token operator">-</span>flags<span class="token punctuation">.</span><span class="token property-access">conf</span> <span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> then </span><span class="code-line"><span class="token number">7</span><span class="token operator">:</span> <span class="token constant">CHROME_USER_FLAGS</span><span class="token operator">=</span><span class="token string">&quot;$(cat $XDG_CONFIG_HOME/chrome-flags.conf)&quot;</span> </span></code></pre></div><h3 id="ulauncher"><a href="#ulauncher" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Ulauncher</h3><p>Ulauncher 的全局热键不再生效. 解决办法参考 <a href="https://github.com/Ulauncher/Ulauncher/wiki/Hotkey-In-Wayland">https://github.com/Ulauncher/Ulauncher/wiki/Hotkey-In-Wayland</a></p><blockquote><p>Fedora and Ubuntu (since 17.04) start <strong>Wayland</strong> session by default. Ulauncher in Wayland does not receive hotkey events when triggered from some windows (like terminal or OS Settings).</p><p>Please follow these steps to fix that:</p><p>Install package <strong>wmctrl</strong> (needed to activate app focus) Open Ulauncher <strong>Preferences</strong> and set <strong>Hotkey</strong> to <strong>something you&#x27;ll never use</strong> Open <strong>Settings</strong> &gt; <strong>Keyboard</strong> (may be named &quot;<strong>Keyboard Shortcuts</strong>&quot;), then scroll down to <strong>Customize Shortcuts</strong> &gt; Custom Shortcuts &gt; <strong>+</strong> In Command enter <code>ulauncher-toggle</code>, set name and shortcut, then click <strong>Add</strong></p></blockquote><p>官方这个文档已经把步骤描述得挺详细了, 这里我就不再说了. 最重要的是你要在 Ulauncher <strong>Preferences</strong> 设置 <strong>Hotkey</strong> 为一个超级复杂的组合键, 并且确保你在日常使用中 100% 都不会触发这个按键.</p><p>因为这个热键实际从 GNOME 的 custom shortcut 那里设置了. 并且触发启动的命令是 <code>ulauncher-toggle</code></p><p>我们看下这个 ulauncher-toggle (位置 <code>/usr/bin/ulauncher-toggle</code> ) 做了啥.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token important shebang">#!/bin/sh</span> </span><span class="code-line"> </span><span class="code-line">dbus-send <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">--session</span> <span class="token punctuation">\</span> </span><span class="code-line"> --print-reply <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">--dest</span><span class="token operator">=</span>net.launchpad.ulauncher <span class="token punctuation">\</span> </span><span class="code-line"> /net/launchpad/ulauncher <span class="token punctuation">\</span> </span><span class="code-line"> net.launchpad.ulauncher.toggle_window </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># dbus-send is asynchronous and sometimes it takes a bit of time for Ulauncher window to be presented</span> </span><span class="code-line"><span class="token function">sleep</span> <span class="token number">0.03</span> </span><span class="code-line"> </span><span class="code-line">wmctrl <span class="token variable parameter">-a</span> <span class="token string">&quot;Ulauncher - Application Launcher&quot;</span> </span></code></pre></div><p>它首先给 ulauncher 的 dbus 接口发送了一个<strong>显示</strong>或<strong>隐藏</strong>窗口的命令 (<code>net.launchpad.ulauncher.toggle_window</code>). 同时, 由于 dbus-send 是异步执行的, 因此实际上脚本不知道 ulauncher 的操作是否已经完成. 不过通常显示一个窗口不算是耗时操作, 因此它这里拍脑袋设定了一个值, 这个值的响应时间对于人操作来说不会有明显的delay, 同时也满足大部分情况下的结果.</p><p>最后, 它需要调用 <code>wmctrl</code> 激活这个窗口, 并获取焦点. 看上去是个 tricks, 不过至少能工作了.</p><h3 id="visual-studio-code"><a href="#visual-studio-code" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>visual-studio-code</h3><p>vs code 当前只能跑在 XWayland 模式, 并且跟 Slack 一样有中文输入卡顿问题.</p><p>当前主分支<a href="https://github.com/microsoft/vscode/issues/109176#event-6364443456">已经修复 Wayland 支持问题</a>, 预计 1.67 会发布.</p><p><a href="https://github.com/microsoft/vscode/commit/648b352b480c51d2a62092230348b54a1c830ec9">https://github.com/microsoft/vscode/commit/648b352b480c51d2a62092230348b54a1c830ec9</a></p><p>主要就是升级 electron到17.3.1</p><p>VSCodium 是跟随ms vscode 版本的, 因此不能解决问题.</p><p>ms 的 insider 版试了下, 窗口显示都有问题. 放弃.</p><p>反正平常也只用它当编辑器使用, 主力还是 Neovim 和 Jetbrains 全家桶.</p><p>2022-04-12 补充更新: vscode 卡顿解决</p><p>参考 <a href="https://code.visualstudio.com/updates/v1_40#_disable-gpu-acceleration">https://code.visualstudio.com/updates/v1_40#_disable-gpu-acceleration</a></p><p>编辑 <code>~/.config/code-flags.conf</code> 加上一行:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token operator">--</span>disable<span class="token operator">-</span>gpu </span></code></pre></div><h3 id="jetbrains全家桶"><a href="#jetbrains全家桶" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Jetbrains全家桶</h3><p>目前 java 还没有 Wayland 原生方案, 因此 Jetbrains 全家桶 是跑在 XWayland 下面, 经测试 fcitx 和 ibus rime 均可正常输入中文.</p><h3 id="smplayer"><a href="#smplayer" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>smplayer</h3><p>smplayer 无法正常在Wayland 下工作. 虽然官方有特别给出说明: <a href="https://blog.smplayer.info/how-to-fix-the-video-problem-on-wayland/">https://blog.smplayer.info/how-to-fix-the-video-problem-on-wayland/</a></p><ol><li>flatpak 版本安装后直接跑不起来, 一运行就崩了.</li><li>Select a different video output in Preferences -&gt; General -&gt; Video, 切换成各各种方式都无法正常工作.</li></ol><p>其中, 硬解 选择 vdpau, Preferences -&gt; General -&gt; Video 选择 drm 可以播放, 但是 mpv 的窗口跑飞了 (&quot;the video being on a separate window&quot;), 其它组合都是 &quot;a black window or a crash when trying to play a video&quot;</p><p>mpv 本身播放正常. 只是 mpv 有些问题, 比如无法在 ui 层面选择 外挂字幕等.</p><p>不过这里有一个解决办法: <a href="https://github.com/darsain/uosc">https://github.com/darsain/uosc</a></p><p>github 上面的安装方法写得并不详细, 我后续会<a href="/post/config-mpv-a-better-player/">单独写文章分享</a>, 详细说一下.</p><div><img alt="" src="https://ttys3.dev/static/assets/screenshot-from-2022-04-09-19-54-04-3J5QZKQR.png" width="1955" height="1113"/></div><p>结论: 视频播放器暂时只能用 GNOME 自带的 Video 播放器顶一下 或者 用 mpv + uosc (推荐)</p><h3 id="其它应用"><a href="#其它应用" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它应用</h3><p>Kitty 中文输入正常, 自然 Neovim 中文输入正常.</p><p>feishu 只能跑在 XWayland 模式, 中文输入正常. 目前无法拖动传文件. 无法使用它内置的截屏功能(当然,我从来就用). 基本上算不太影响使用吧.</p><p>jetbrains-toolbox 也是跑在 XWayland 模式, 目前看来使用上没啥影响.</p><p>LibreOffice Wayland and HiDPI To work around issues with scaling UI elements in Wayland on HiDPI screens, use the gtk3 VCL UI interface. <a href="https://wiki.archlinux.org/title/LibreOffice#Wayland_and_HiDPI">https://wiki.archlinux.org/title/LibreOffice#Wayland_and_HiDPI</a> 这一点在 GNOME 42 下会默认检测用 gtk3, 因此默认就 OK</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://fedoraproject.org/wiki/Changes/WaylandByDefaultOnNVIDIA">https://fedoraproject.org/wiki/Changes/WaylandByDefaultOnNVIDIA</a></p><p><a href="https://wiki.archlinux.org/title/NVIDIA#DRM_kernel_mode_setting">https://wiki.archlinux.org/title/NVIDIA#DRM_kernel_mode_setting</a></p><p><a href="https://wiki.archlinux.org/title/GDM#Wayland_and_the_proprietary_NVIDIA_driver">https://wiki.archlinux.org/title/GDM#Wayland_and_the_proprietary_NVIDIA_driver</a></p><p><a href="https://wiki.archlinux.org/title/Wayland#Display_managers">https://wiki.archlinux.org/title/Wayland#Display_managers</a></p><p><a href="https://wiki.archlinux.org/title/GNOME#GNOME_applications_in_Wayland">https://wiki.archlinux.org/title/GNOME#GNOME_applications_in_Wayland</a></p><p><a href="https://fedoraproject.org/wiki/How_to_debug_Wayland_problems">https://fedoraproject.org/wiki/How_to_debug_Wayland_problems</a></p><p><a href="https://cubethethird.wordpress.com/2017/06/07/mixed-feelings-about-wayland-on-gnome/">https://cubethethird.wordpress.com/2017/06/07/mixed-feelings-about-wayland-on-gnome/</a></p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_the_desktop_environment_in_rhel_8/customizing-gnome-desktop-features_using-the-desktop-environment-in-rhel-8#changing-behavior-when-pressing-the-powerbutton_customizing-gnome-desktop-features">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_the_desktop_environment_in_rhel_8/customizing-gnome-desktop-features_using-the-desktop-environment-in-rhel-8#changing-behavior-when-pressing-the-powerbutton_customizing-gnome-desktop-features</a></p><p><a href="https://www.reddit.com/r/Slack/comments/obgrac/slow_and_sluggish_typing_on_linux/">https://www.reddit.com/r/Slack/comments/obgrac/slow_and_sluggish_typing_on_linux/</a></p><p><a href="https://github.com/microsoft/vscode/issues/109176#event-6364443456">https://github.com/microsoft/vscode/issues/109176#event-6364443456</a></p><p><a href="https://github.com/microsoft/vscode/commit/648b352b480c51d2a62092230348b54a1c830ec9">https://github.com/microsoft/vscode/commit/648b352b480c51d2a62092230348b54a1c830ec9</a></p><p><a href="https://a-wing.top/linux/2022/01/03/translate_wayland.html">https://a-wing.top/linux/2022/01/03/translate_wayland.html</a></p><p><a href="https://github.com/flameshot-org/flameshot/issues/2186">https://github.com/flameshot-org/flameshot/issues/2186</a></p><p>Are we Wayland yet? <a href="https://arewewaylandyet.com/">https://arewewaylandyet.com/</a></p><p><a href="https://wiki.archlinux.org/title/Flameshot#Flameshot_does_not_use_currently_visible_windows">https://wiki.archlinux.org/title/Flameshot#Flameshot_does_not_use_currently_visible_windows</a></p><p><a href="https://github.com/fcitx/fcitx5/issues/263">https://github.com/fcitx/fcitx5/issues/263</a></p><p><a href="https://www.fosskers.ca/en/blog/wayland">https://www.fosskers.ca/en/blog/wayland</a></p> Sat, 09 Apr 2022 03:10:39 GMT ttyS3 GNOMEupgradeWaylandxdg https://ttys3.dev/blog/how-we-make-gitlab-golangci-lint-runs-50-times-faster How We Make Gitlab Golangci-lint Runs 50 Times Faster https://ttys3.dev/blog/how-we-make-gitlab-golangci-lint-runs-50-times-faster <p>自从我们迁移到 k8s, 我们观察到 k8s 集群里的 gitlab CI runner 在跑 golangci-lint 的时候比本机跑慢很多.</p><p>本机一般几十秒就能搞定的事情, 在跑 CI 的时候, 基本上都要花上几分钟甚至几十分钟. (依项目代码量而异)</p><p>当然, 由于 CI 都是自动跑的, 大部分时间我们基本上不会花时间去刻意观察 CI 的执行. 因此慢一点其实也不会影响什么.</p><p>这个周末正好趁疫情居家哪也去不了, 研究了一下怎么想办法将速度优化.</p><p>起初我以为是因为普通云盘的 IO 性能低下导致的问题, 因为我们的节点的 CPU 和 内核配置都还算不错, 不至于跑个 CI 都会因为这个影响到速度.</p><p>但是经过研究, 我发现其实大部分时间花在重复地一次又一次地加载go mod 和 重复地进行代码静态分析.</p><p>没有优化之前的 CI lint stage 日志大概是这样的:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">golangci-lint run <span class="token variable parameter">-v</span> </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;[lintersdb] Active 33 linters: [bidichk bodyclose dogsled dupl durationcheck errorlint exhaustive exportloopref forbidigo gci gochecknoglobals gochecknoinits goconst gocritic gofmt gofumpt goimports gomodguard goprintffuncname gosimple importas ineffassign makezero misspell nilerr revive rowserrcheck sqlclosecheck staticcheck typecheck unconvert unused wastedassign]&quot;</span> </span><span class="code-line"><span class="token punctuation">..</span>. </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;[loader] Go packages loading at mode 575 (compiled_files|exports_file|imports|types_sizes|deps|files|name) took 1m10.18730135s&quot;</span> </span><span class="code-line"><span class="token punctuation">..</span>. </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;[runner] linters took 7m43.677383001s with stages: goanalysis_metalinter: 7m43.625988553s&quot;</span> </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;File cache stats: 148 entries of total size 521.9KiB&quot;</span> </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;Memory: 1015 samples, avg is 352.2MB, max is 1469.0MB&quot;</span> </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;Execution took 8m53.886795985s&quot;</span> </span></code></pre></div><p>注意, <strong>goanalysis_metalinter</strong> 并不是一个具体的 linter 的名字, 而是指的最主要的 linter 执行阶段, 这里花了 <code>7m43.625988553s</code>. 另一个耗时比较小的stage 是 <strong>Go packages loading</strong></p><p>所以, 其实最主要的原因还不是磁盘 io. 主要原因还是 golangci-lint 的每次分析结果都没有复用. 每次都要从0重新分析, 即使只修改了一行代码, 整个执行时间也无法减少.</p><p>于是查看 golangci-lint 文档, 看它有没有类似的缓存策略.</p><h2 id="golangci-lint-缓存目录配置"><a href="#golangci-lint-缓存目录配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>golangci-lint 缓存目录配置</h2><p>文档对于 cache 的介绍, 只是一笔带过, 只有一句话描述, 放在配置页的最底部, 那么地不起眼, 以至于我多次看过这个文档而, 从来没引起过我的注意.</p><p><a href="https://golangci-lint.run/usage/configuration/#cache">https://golangci-lint.run/usage/configuration/#cache</a></p><blockquote><p>GolangCI-Lint stores its cache in the <a href="https://golang.org/pkg/os/#UserCacheDir">default user cache directory</a>.</p><p>You can override the default cache directory with the environment variable <code>GOLANGCI_LINT_CACHE</code>; the path must be absolute.</p></blockquote><p>这个文档确实比较含糊. 什么是用户默认缓存目录? 这里直接指向了 golang 标准库的文档:</p><blockquote><p>On Unix systems, it returns <code>$XDG_CACHE_HOME</code> as specified by  <a href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html">https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html</a>  if non-empty, else <code>$HOME/.cache</code>. On Darwin, it returns <code>$HOME/Library/Caches</code>. On Windows, it returns <code>%LocalAppData%</code>. On Plan 9, it returns <code>$home/lib/cache</code>.</p></blockquote><p>我们的容器镜像都是 Linux 作为 base image 的, 因此自然是<code>$HOME/.cache</code></p><p>但是实际上它的路径是: <code>$HOME/.cache/golangci-lint</code></p><p>可以通过<code>GOLANGCI_LINT_CACHE</code>设置一个<strong>绝对路径</strong>覆盖这一默认行为. 文档特别强调要用<strong>绝对路径</strong>.</p><p>在 gitlab CI yaml 文件中, 我们可以这样设置:</p><div class="relative"><pre><code class="code-highlight language-yaml"><span class="code-line"><span class="token atrule key">variables</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">GOLANGCI_LINT_CACHE</span><span class="token punctuation">:</span> /go/.cache/golangci<span class="token punctuation">-</span>lint </span><span class="code-line"> <span class="token atrule key">GOCACHE</span><span class="token punctuation">:</span> /go/.cache/go<span class="token punctuation">-</span>build </span><span class="code-line"> <span class="token atrule key">GOMODCACHE</span><span class="token punctuation">:</span> /go/pkg/mod </span><span class="code-line"> <span class="token atrule key">GOPATH</span><span class="token punctuation">:</span> /go </span></code></pre></div><p>当然, 这里除了设置了 <code>GOLANGCI_LINT_CACHE</code> , 我们还设置了 <code>GOCACHE</code>, <code>GOMODCACHE</code> 和 <code>GOPATH</code> 这三个对于 go 构建速度提升非常重要的环境变量 (它们对于 golangci-lint 速度提升几乎没有帮助, 但是对于后面的 go build 阶段非常有用).</p><h2 id="gitlab-ci-缓存配置"><a href="#gitlab-ci-缓存配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Gitlab CI 缓存配置</h2><p>我们用的是兼容s3协议的MinIO作为Gitlab CI 缓存后端. 它足够简单.</p><p>由于我们有很多个 Gitlab runner, 默认情况下, 缓存在各个runner 之间是不共享的, Gitlab 的实现非常简单, 即在缓存 key 前面自动加上了 runner id. 而这明显跟我们的需求不太符合. 我们不希望在一个runner上面跑好的缓存, 当下次 CI 调度到不同的 runner 的时候, 这个缓存不能利用上. Gitlab 当然也考虑到了这种需求, 只需要设置 <code>CACHE_SHARED</code> 为 <code>true</code> 即可.</p><p>具体可参考 <a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscache-section">https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscache-section</a></p><p>当然, Gitlab 启用了 cache 支持, 具体在 CI 的时候是否启用, 是通过 yaml 文件 <code>cache</code> 配置来实现的, demo 如下:</p><div class="relative"><pre><code class="code-highlight language-yaml"><span class="code-line"><span class="token atrule key">golangci-lint</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">stage</span><span class="token punctuation">:</span> run<span class="token punctuation">-</span>linter </span><span class="code-line"> <span class="token atrule key">image</span><span class="token punctuation">:</span> docker.io/golangci/golangci<span class="token punctuation">-</span>lint<span class="token punctuation">:</span>v1.45.0 </span><span class="code-line"> <span class="token atrule key">script</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> golangci<span class="token punctuation">-</span>lint version </span><span class="code-line"> <span class="token punctuation">-</span> golangci<span class="token punctuation">-</span>lint run <span class="token punctuation">-</span>v <span class="token punctuation">-</span><span class="token punctuation">-</span>color always <span class="token punctuation">-</span><span class="token punctuation">-</span>out<span class="token punctuation">-</span>format colored<span class="token punctuation">-</span>line<span class="token punctuation">-</span>number </span><span class="code-line"> <span class="token atrule key">cache</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">key</span><span class="token punctuation">:</span> go<span class="token punctuation">-</span>cache<span class="token punctuation">-</span>$<span class="token punctuation">{</span>CI_PROJECT_PATH_SLUG<span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">paths</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> go </span></code></pre></div><p>注意这里的 cache.key 配置, 为了避免不同的项目 CI 时缓存互相更新打架, 我们加上了<strong>项目路径</strong> (<code>CI_PROJECT_PATH_SLUG</code>)后缀, 这样每个项目都拥有自己独立但多 runner 共享的 cache.</p><p><code>CI_PROJECT_PATH_SLUG</code> 是专门做这种事情的, 它把 <code>/</code> 等替换成了 <code>-</code>, 方便用作 key name 或 file name.</p><p>回头看一下我们设置的环境变量, 其实这里涉及到一个缓存目录规划问题.</p><p>我们配置了一个顶级 cache 目录, 然后这个目录用来缓存 go mod (<code>GOPATH: /go</code> 和 <code>GOMODCACHE: /go/pkg/mod</code>), go build cache (<code>GOCACHE: /go/.cache/go-build</code>) 和 golangci-lint cache (<code>GOLANGCI_LINT_CACHE: /go/.cache/golangci-lint</code>). 所以这些环境变量名和路径都不是随意选的, 而是有规划的.</p><p>关于<a href="https://docs.gitlab.com/ee/ci/yaml/#cachepaths">cache.path</a>, 有一个约束, 它只能是<strong>相对路径</strong></p><blockquote><p>An array of paths <strong>relative</strong> to the project directory (<code>$CI_PROJECT_DIR</code>). You can use wildcards that use <a href="https://en.wikipedia.org/wiki/Glob_(programming)">glob</a> patterns:</p><ul><li>In <a href="https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2620">GitLab Runner 13.0 and later</a>, <a href="https://pkg.go.dev/github.com/bmatcuk/[email protected]?tab=doc#Match"><code>doublestar.Glob</code></a>.</li><li>In GitLab Runner 12.10 and earlier, <a href="https://pkg.go.dev/path/filepath#Match"><code>filepath.Match</code></a>.</li></ul></blockquote><p>也许你发现问题了, 我们用的go mod 缓存目录是 <code>GOMODCACHE: /go/pkg/mod</code></p><p>然后 Gitlab cache 只会把缓存内容释放到当前项目的CI目录. 那么我们为什么不用 <code>$CI_PROJECT_DIR/pkg/mod</code> ?</p><p>另外, 这个释放的缓存不在它应该在的位置, 我们怎么样利用上这个缓存?</p><p>答案就是: 因为 golangci-lint 不支持真正意义上的 <code>skip-dirs</code></p><p>我们特意测试过, skip-dirs 并不像字面意思, skip-dirs 的工作方式是: 即使是在skip-dirs配置里的目录, 也同样进行静态分析, 但是如果有任何违反linter规则的问题, 不予以报告.</p><p>所以, 我们不能让 golangci-lint 去扫描这些 go mod, 我们就得想办法把 项目 CI 目录下的 缓存目录, 在执行 golangci-lint 之前移动到其它地方, 然后在 golangci-lint 执行完毕之后, 再移动回来 (因为这个时候Gitlab会将配置的cache.path目录全部打包push到MinIO, 如果不move回来, 就没机会push缓存了). 这个操作可以通过 Gitlab 的 before_script 和 after_script 来实现. 对于 build 阶段 ( <code>go build</code> 构建二进制以及容器镜像构建) 我们没有必要这样移动, 但是一定要记得将这个大于 1GB 的缓存目录(里面有 go mod 和 go build cache等, 体积基本上会超过1GB) 排除在 docker ignore, 要不然会拖慢 docker build. 最简单的办法就是, 我们不区分 lint 和 build 阶段, 统一做两次move (移走缓存是为了 golangci-lint, 移回来是为了Gitlab能push缓存).</p><div class="relative"><pre><code class="code-highlight language-yaml"><span class="code-line"><span class="token atrule key">.script_before</span><span class="token punctuation">:</span> <span class="token important">&amp;go_with_cache_before</span> <span class="token punctuation">|</span><span class="token string scalar"> </span></span><span class="code-line"><span class="token string scalar"> echo &quot;---------------------------- begin before_script&quot;</span> </span><span class="code-line"> </span><span class="code-line"> if <span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token punctuation">-</span>d go <span class="token punctuation">]</span><span class="token punctuation">]</span>; then </span><span class="code-line"> echo &quot;<span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">-</span> after cache get<span class="token comment"># move cwd go to ${GOPATH}&quot;</span> </span><span class="code-line"> if <span class="token punctuation">[</span> &quot;$<span class="token punctuation">{</span>DEBUG_GITLAB_CI_COMMAND<span class="token punctuation">}</span>&quot; = &quot;true&quot; <span class="token punctuation">]</span>; then </span><span class="code-line"> du <span class="token punctuation">-</span>sh go </span><span class="code-line"> fi </span><span class="code-line"> rm <span class="token punctuation">-</span>rf &quot;$<span class="token punctuation">{</span>GOPATH<span class="token punctuation">}</span>&quot; <span class="token important">&amp;&amp;</span> mv go / </span><span class="code-line"> else </span><span class="code-line"> echo &quot;no cache<span class="token tag">!</span><span class="token tag">!</span><span class="token tag">!</span>&quot; </span><span class="code-line"> fi </span><span class="code-line"> echo &quot;<span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">-</span> end before_script&quot; </span><span class="code-line"> </span><span class="code-line"><span class="token atrule key">.script_after</span><span class="token punctuation">:</span> <span class="token important">&amp;go_with_cache_after</span> <span class="token punctuation">|</span><span class="token string scalar"> </span></span><span class="code-line"><span class="token string scalar"> echo &quot;---------------------------- begin after_script&quot;</span> </span><span class="code-line"> </span><span class="code-line"> if <span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token punctuation">-</span>d &quot;$<span class="token punctuation">{</span>GOPATH<span class="token punctuation">}</span>&quot; <span class="token punctuation">]</span><span class="token punctuation">]</span>; then </span><span class="code-line"> echo &quot;<span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">-</span> before cache put<span class="token comment"># move ${GOPATH} to cwd&quot;</span> </span><span class="code-line"> mv &quot;$<span class="token punctuation">{</span>GOPATH<span class="token punctuation">}</span>&quot; . </span><span class="code-line"> else </span><span class="code-line"> echo &quot;no $<span class="token punctuation">{</span>GOPATH<span class="token punctuation">}</span> dir<span class="token punctuation">,</span> this is OK if no cache defined&quot; </span><span class="code-line"> fi </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"> echo &quot;<span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">---</span><span class="token punctuation">-</span> end after_script&quot; </span><span class="code-line"> </span><span class="code-line"><span class="token atrule key">before_script</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token important">*init_git_credentials</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token important">*go_with_cache_before</span> </span><span class="code-line"> </span><span class="code-line"><span class="token atrule key">after_script</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token important">*go_with_cache_after</span> </span></code></pre></div><p>注意, 这里用了一个小技巧: yaml literal block + yaml anchors</p><p>literal block 可以使我们写多行shell脚本更加方便, <a href="https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#anchors">Gitlab CI YAML 是支持 anchors </a>的, 这让我们写的多行shell脚本可以复用.</p><p>注意这里有一个 <code>init_git_credentials</code> anchor 引用, 我没有给出定义, 这个东西太简单, 就是 echo 然后 ssh-add 一下把 public key 加到 ssh-agent 而已. 并且跟当前我们要讨论的重点无关, 因此这里不写. 有兴趣的可以<a href="https://docs.gitlab.com/ee/ci/ssh_keys/#ssh-keys-when-using-the-docker-executor">查看文档</a>.</p><p>然后我们再对比看一下执行时间(同一个仓库, 同样的配置):</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token comment"># before optimization</span> </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;[runner] linters took 7m43.677383001s with stages: goanalysis_metalinter: 7m43.625988553s&quot;</span> </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;File cache stats: 148 entries of total size 521.9KiB&quot;</span> </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;Memory: 1015 samples, avg is 352.2MB, max is 1469.0MB&quot;</span> </span><span class="code-line"><span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;Execution took 8m53.886795985s&quot;</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># after optimization</span> </span><span class="code-line"><span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token string">&quot;Mar 19 23:31:07.273&quot;</span> <span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;[runner] linters took 291.185017ms with stages: goanalysis_metalinter: 239.743075ms&quot;</span> </span><span class="code-line"><span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token string">&quot;Mar 19 23:31:07.273&quot;</span> <span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;File cache stats: 0 entries of total size 0B&quot;</span> </span><span class="code-line"><span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token string">&quot;Mar 19 23:31:07.273&quot;</span> <span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;Memory: 12 samples, avg is 58.9MB, max is 87.5MB&quot;</span> </span><span class="code-line"><span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token string">&quot;Mar 19 23:31:07.273&quot;</span> <span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;Execution took 1.08783787s&quot;</span> </span></code></pre></div><p>内存占用从平均 352M 下降到 60M 不到. 内存占用峰值从 1.5G 左右 下降到 90M 不到.</p><p>lint 执行时间从接近9分钟下降到只需要1秒左右.</p><p>当然, 这是代码变化特别小的情况. 按这个算的话, 是快了 500多倍.</p><p>对于日常提交, 一般可以将 lint 执行时间控制在10s 以内, 按这个来算, (480+53)/10 = 53.3 差不多是原来的50多倍吧:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token string">&quot;Mar 19 21:33:04.218&quot;</span> <span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;[runner] linters took 6.151722993s with stages: goanalysis_metalinter: 6.099292807s&quot;</span> </span><span class="code-line"><span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token string">&quot;Mar 19 21:33:04.218&quot;</span> <span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;File cache stats: 90 entries of total size 417.9KiB&quot;</span> </span><span class="code-line"><span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token string">&quot;Mar 19 21:33:04.218&quot;</span> <span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;Memory: 88 samples, avg is 335.2MB, max is 621.5MB&quot;</span> </span><span class="code-line"><span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token string">&quot;Mar 19 21:33:04.218&quot;</span> <span class="token variable assign-left">level</span><span class="token operator">=</span>info <span class="token variable assign-left">msg</span><span class="token operator">=</span><span class="token string">&quot;Execution took 8.665056149s&quot;</span> </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://docs.gitlab.com/ee/ci/variables/predefined_variables.html">https://docs.gitlab.com/ee/ci/variables/predefined_variables.html</a></p><p><a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscache-section">https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscache-section</a></p><p><a href="https://min.io/">https://min.io/</a></p><p><a href="https://docs.gitlab.com/ee/ci/caching/#how-archiving-and-extracting-works">https://docs.gitlab.com/ee/ci/caching/#how-archiving-and-extracting-works</a></p><p><a href="https://docs.gitlab.com/ee/ci/yaml/script.html">https://docs.gitlab.com/ee/ci/yaml/script.html</a></p><p><a href="https://stackoverflow.com/questions/42560083/multiline-yaml-string-for-gitlab-ci-gitlab-ci-yml/55347979#55347979">https://stackoverflow.com/questions/42560083/multiline-yaml-string-for-gitlab-ci-gitlab-ci-yml/55347979#55347979</a></p><p><a href="https://docs.gitlab.com/ee/ci/yaml/#cache">https://docs.gitlab.com/ee/ci/yaml/#cache</a></p><p><a href="https://docs.gitlab.com/ee/ci/yaml/#cachepaths">https://docs.gitlab.com/ee/ci/yaml/#cachepaths</a></p><p><a href="https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html">https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html</a></p><p><a href="https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#anchors">https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#anchors</a></p><p><a href="https://docs.gitlab.com/ee/ci/ssh_keys/#ssh-keys-when-using-the-docker-executor">https://docs.gitlab.com/ee/ci/ssh_keys/#ssh-keys-when-using-the-docker-executor</a></p> Sun, 20 Mar 2022 14:54:54 GMT ttyS3 gitlabgolangci-lintlinteroptimization https://ttys3.dev/blog/k8s-telepresence-in-action Telepresence实践及踩坑记 https://ttys3.dev/blog/k8s-telepresence-in-action <blockquote><p>Telepresence 是一个开源工具,可让您在本地运行单个服务,同时将该服务连接到远程 Kubernetes 集群</p></blockquote><p><a href="https://www.telepresence.io/about/">https://www.telepresence.io/about/</a></p><h2 id="为什么需要-telepresence"><a href="#为什么需要-telepresence" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>为什么需要 Telepresence</h2><p>k8s pod IP 由 CNI 分配, 通信是走 overlay 网络, 容器之间的通信都是基于cluser IP.</p><p>cluser IP 并不像我们平常所用的 IP. 它只能在 k8s 集群内部使用.</p><p>虽然我们可以通过配置 overlay 网络的网段 跟 k8s node 的网段在一个大的子网段, 然后通过 vpn 把对应网段的流量路由到overlay 网络, 我们完全可以通过 <code>kubectl get po -o wide</code> 获取到 pod IP, 然后访问服务.</p><p>也就是说, 如果我们在本机想运行一个服务, 不依赖 Telepresence 这种工具是完全可行的.</p><p>但是, 其实我们每个服务都有配置, 配置里面写的grpc 服务地址可能像这样: <code>xxxx.svc.cluster.local:1234</code>, 如果我们想要服务的配置不经过任何修改, 直接在本机运行.</p><p>有没有办法呢? 答案当然是有的, 设置 hosts 啊. <code>kubectl get po -o wide</code> 获取到 pod IP 和 pod name, (假设 pod name 和 service name 命名是一致的,即从 pod name 我们可以字面上得到 service name) 然后拼接成k8s里面的 DNS name <code>xxxx.svc.cluster.local</code>, 将这个域名映射到 pod IP 即可. 假设我们写了这样一个脚本, 但是当 pod 被调试到不同的node, 或者 pod 重建之后, 其 pod IP 必然会改变, 这个时候我们又要手动去重新生成这个 hosts 文件. 总体操作来说, 还是挺麻烦的.</p><p>另一个问题是, 团队内部有很多人, 要让所有人都都学会这一招操作, 可能会有些困难, 或者说, 这种方式, 对用户不太好友.</p><p>这个时候, Telepresence 横空出世.</p><p>在 k8s 官方文档中, &quot;<a href="https://kubernetes.io/zh/docs/tasks/debug-application-cluster/local-debugging/">本地开发和调试服务</a>&quot; 一节, Telepresence 是唯一介绍的工具.</p><p>对于用户来说, Telepresence 提供了3个非常重要的功能:</p><ol><li>cluster 域名解析</li><li>cluster 流量代理</li><li>cluster 流量拦截</li></ol><p><strong>域名解析</strong> 可以使我们在本地开发机器直接解析如 <code>xxxx.svc.cluster.local</code> 这种域名.</p><p>(注: mac 下面机制不太一样, 不可以使用dig测试,但是可以用curl)</p><p>你可以像查询其它域名一样使用命令行 dig 工具进行查询, 如 <code>dig kubernetes.default</code></p><p>光有域名解析还不够, 我们还是没法连接集群内的其它服务, 因此 <strong>流量代理</strong> 功能的作用就体验出来了.</p><p>在 Linux 下面, Telepresence 会建立一个名叫 <code>tel0</code> 的 tun 设备. 然后通过 systemd-resolved 服务将集群命令空间的 cluster domain 添加到这个设备. 通过<code>resolvectl status tel0</code>可以查看到当前有哪些命令空间被添加进来了:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">resolvectl status tel0 </span><span class="code-line">Link <span class="token number">66</span> <span class="token punctuation">(</span>tel0<span class="token punctuation">)</span> </span><span class="code-line"> Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6 </span><span class="code-line"> Protocols: <span class="token variable parameter">-DefaultRoute</span> +LLMNR <span class="token variable parameter">-mDNS</span> <span class="token variable parameter">-DNSOverTLS</span> <span class="token variable assign-left">DNSSEC</span><span class="token operator">=</span>no/unsupported </span><span class="code-line">Current DNS Server: <span class="token number">10.0</span>.165.145 </span><span class="code-line"> DNS Servers: <span class="token number">10.0</span>.165.145 </span><span class="code-line"> DNS Domain: ~ambassador ~argocd ~cluster.local ~db ~default ~devops ~istio-system ~jaeger ~kube-public ~kube-system ~nacos ~observability </span></code></pre></div><p><strong>流量拦截</strong> 可以将集群里指定服务的流量拦截并转发到本地开发机器, 比如调试复杂的 app 业务接口时,非常方便.</p><p>这个非常有用, 但是老灯平常一般都不用这个. 因为我们的服务都有注入 istio side car. 而 Telepresence 的拦截原理其实也跟 istio 类似, 也是利用 side car 注入然后代理流量. 但是同一个 pod 的流量, 不能同时被 istio 接管, 然后又被 Telepresence 接管. 这一点我后面再详细说怎么解决.</p><h2 id="日常使用"><a href="#日常使用" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>日常使用</h2><p><code>telepresence connect</code> 连接</p><p><code>telepresence status</code> 查看连接状态</p><p><code>curl -ik https://kubernetes.default</code> 测试连接成功与否( 有任意响应就是成功)</p><p><code>telepresence quit -u -r</code> 断开连接并退出user 和 root daemon</p><h2 id="dns-解析原理"><a href="#dns-解析原理" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>DNS 解析原理</h2><p>这部分主要参考 <a href="https://www.telepresence.io/docs/latest/reference/routing/">https://www.telepresence.io/docs/latest/reference/routing/</a></p><h3 id="linux-systemd-resolved-resolver"><a href="#linux-systemd-resolved-resolver" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Linux systemd-resolved resolver</h3><p>以 Linux 上面的实现为例, 简单来说, Telepresence 就是新建一 tun 设备, 这个设备的流量会代理到 k8s 里的Telepresence traffic manager ( 负责流量转发等). tun 设备的 DNS 被设置成了 k8s 集群的 DNS (一般是 coredns 啦). Telepresence 会 watch 整个集群的所有命名空间, 因此, 当发生变量的时候, DNS link domain 会被自动更新.</p><p>然后, 设置哪此命令空间后缀要通过这个 DNS 查询 是通过 systemd-resolved 的服务的<a href="https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html"> dbus 接口</a> <code>SetLinkDomains</code> 操作的. 设置 DNS 是通过 <code>SetLinkDNS</code></p><p>这种操作, 其实就相当于在 <code>/etc/systemd/resolved.conf.d</code> 下面新建一 <code>k8s.conf</code> 文件, 内容类似于:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"># https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>learn<span class="token punctuation">.</span><span class="token property-access">hashicorp</span><span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>tutorials<span class="token operator">/</span>consul<span class="token operator">/</span>dns<span class="token operator">-</span>forwarding#systemd<span class="token operator">-</span>resolved<span class="token operator">-</span>setup </span><span class="code-line"><span class="token punctuation">[</span><span class="token maybe-class-name">Resolve</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token constant">DNS</span><span class="token operator">=</span><span class="token number">10.0</span><span class="token number">.165</span><span class="token number">.145</span><span class="token operator">:</span><span class="token number">53</span> </span><span class="code-line"><span class="token constant">DNSSEC</span><span class="token operator">=</span><span class="token boolean">false</span> </span><span class="code-line"><span class="token maybe-class-name">Domains</span><span class="token operator">=</span><span class="token operator">~</span>ambassador <span class="token operator">~</span>argocd <span class="token operator">~</span>cluster<span class="token punctuation">.</span><span class="token property-access">local</span> <span class="token operator">~</span>db <span class="token operator">~</span><span class="token keyword module">default</span> <span class="token operator">~</span>devops <span class="token operator">~</span>istio<span class="token operator">-</span>system <span class="token operator">~</span>jaeger <span class="token operator">~</span>kube<span class="token operator">-</span><span class="token keyword">public</span> <span class="token operator">~</span>kube<span class="token operator">-</span>system <span class="token operator">~</span>nacos <span class="token operator">~</span>observability </span></code></pre></div><p>只不过, 通过 dbus 可以动态的修改, 更加方便.</p><h3 id="linux-overriding-resolver"><a href="#linux-overriding-resolver" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Linux overriding resolver</h3><blockquote><p>Linux systems that aren&#x27;t configured with <code>systemd-resolved</code> will use this resolver. A Typical case is when running Telepresence <a href="https://www.telepresence.io/docs/latest/reference/inside-container">inside a docker container</a>. During initialization, the resolver will first establish a <em>fallback</em> connection to the IP passed as <code>--dns</code>, the one configured as <code>local-ip</code> in the <a href="https://www.telepresence.io/docs/latest/reference/config/#dns">local DNS configuration</a>, or the primary <code>nameserver</code> registered in <code>/etc/resolv.conf</code>. It will then use iptables to actually override that IP so that requests to it instead end up in the overriding resolver, which unless it succeeds on its own, will use the <em>fallback</em>.</p></blockquote><p>即, 对于不支持 systemd-resolved 的 Linux 系统(一般是非常老的那种), Telepresence 会自己起一个 DNS 代理服务, 一般是监听随机端口, 然后再将系统 DNS 设置成 TelepresenceDNS 代理服务的地址. 即解析的时候会先查集群, 没有结果会 fallback 到本机原来的 DNS, 比如 Google public DNS 等解析其它域名.这个会影响其它应用的使用, 这种实现方式不太好, 以老灯的使用经验来看, 这种方式也不太稳定. 容易造成问题.</p><h3 id="macos-resolver"><a href="#macos-resolver" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>macOS resolver</h3><p>在 macOS 下面是通过 resolver hooks 实现的.</p><blockquote><p>This resolver hooks into the macOS DNS system by creating files under <code>/etc/resolver</code>. Those files correspond to some domain and contain the port number of the Telepresence resolver. Telepresence creates one such file for each of the currently mapped namespaces and <code>include-suffixes</code> option. The file <code>telepresence.local</code> contains a search path that is configured based on current intercepts so that single label names can be resolved correctly.</p></blockquote><h2 id="troubleshooting"><a href="#troubleshooting" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>troubleshooting</h2><h3 id="1-流量拦截不生效"><a href="#1-流量拦截不生效" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. 流量拦截不生效</h3><p>测试过程中发现 流量拦截 与 注入的 istio-proxy 容器存在冲突,即当 istio-proxy 存在时,流量全部被 istio-proxy 接管了,<code>traffic-agent</code> 没有成功拦截到流量。</p><p>目前我暂时的一个 hack 方法是取消 istio-proxy sidecar注入:</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">diff --git a/develop/overlays/my_app/deployment.yaml b/develop/overlays/my_app/deployment.yaml </span><span class="code-line">index 1049d335..26ee38d4 100644 </span><span class="code-line deleted"><span class="token coord">--- a/develop/overlays/my_app/deployment.yaml</span> </span><span class="code-line inserted"><span class="token coord">+++ b/develop/overlays/my_app/deployment.yaml</span> </span><span class="code-line">@@ -4,6 +4,9 @@ metadata: </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> name: ttys3 </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">spec: </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> template: </span></span></span><span class="code-line inserted"><span class="token unchanged"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> metadata: </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> annotations: </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> sidecar.istio.io/inject: &quot;false&quot; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> spec: </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> containers: </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> - name : my-app </span></span></span></code></pre></div><p><code>traffic-agent</code> 日志查看: <code>stern --tail 100 ttys3-my-app -c traffic-agent</code></p><p>如果是采用 argo cd rollout:</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">diff --git a/develop/overlays/my-app/rollout.yaml b/develop/overlays/my-app/rollout.yaml </span><span class="code-line">index 263eab87c..bbc44c378 100644 </span><span class="code-line deleted"><span class="token coord">--- a/develop/overlays/my-app/rollout.yaml</span> </span><span class="code-line inserted"><span class="token coord">+++ b/develop/overlays/my-app/rollout.yaml</span> </span><span class="code-line">@@ -6,6 +6,9 @@ metadata: </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">spec: </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> template: </span></span></span><span class="code-line inserted"><span class="token unchanged"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> metadata: </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> annotations: </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> sidecar.istio.io/inject: &quot;false&quot; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> spec: </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> securityContext: </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> runAsUser: 1000 </span></span></span></code></pre></div><h3 id="2-连接不上"><a href="#2-连接不上" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. 连接不上</h3><p>使用新版本的 telepresence v2.x.x 如果“重复” 出现 (偶尔一次可能是意外)以下错误:</p><blockquote><p>⁣telepresence: error: the <strong>port-forward</strong> connection to the traffic manager timed out. The current timeout 20s can be configured as timeouts.trafficManagerConnect</p></blockquote><p>⁣ ⁣或 ⁣</p><blockquote><p>⁣telepresence: error: the traffic manager gRPC API timed out. The current timeout 20s can be configured as timeouts.trafficManagerAPI in /Users/tomeee/Library/Application Support/telepresence/config.yml ⁣</p></blockquote><p>⁣类似错误, ⁣说明同一集群里有多个人使用不同版本 v2 的客户端互相在打架。 当 telepresence 连接的时候, 如果与当前版本匹配的 traffic manager不存在, 则会自动安装与当前版本匹配的 traffic manager. 当不同的人, 从不同的地方, 下载了不同的版本, 都在连接同一个集群的时候, 问题就发生了.</p><p>解决方案: 同一集群所有人统一使用相同版本的客户端 (版本号要完全相同,对于 nightly 版, 小版本号和commit hash 都要相同) sys op 对整个集群的 rbac 做更加安全地配置, 禁止除 devops 组之外的其它开发人员拥有可以 <code>ambassador</code> 命名空间下资源的更新权限, 这样就可以阻止开发人员在使用telepresence 连接的时候无意中错误地在不停地安装各种版本的 traffic manager. 但是为了保证开发人员可以正常使用, <code>list</code> resource &quot;<code>namespaces</code>&quot;权限一定要给, 然后就是 <code>create</code> resource &quot;pods/portforward&quot; in API group &quot;&quot; in the namespace &quot;<code>ambassador</code>&quot; 的权限. ⁣ Client / Root Daemon / User Daemon 3 个版本号一定要完全一致:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">❯ telepresence version </span><span class="code-line">Client: v2.5.4 <span class="token punctuation">(</span>api v3<span class="token punctuation">)</span> </span><span class="code-line">Root Daemon: v2.5.4 <span class="token punctuation">(</span>api v3<span class="token punctuation">)</span> </span><span class="code-line">User Daemon: v2.5.4 <span class="token punctuation">(</span>api v3<span class="token punctuation">)</span> </span></code></pre></div><p>参考官方 issue: <a href="https://github.com/telepresenceio/telepresence/issues/1652">https://github.com/telepresenceio/telepresence/issues/1652</a></p><p><a href="https://github.com/telepresenceio/telepresence/issues/1689">https://github.com/telepresenceio/telepresence/issues/1689</a></p><h3 id="3-如何彻底卸载"><a href="#3-如何彻底卸载" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. 如何彻底卸载</h3><p>一般情况下可以直接 <code>telepresence uninstall --everything</code> 搞定.</p><p>如果需要手动卸载可以这样操作:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">k delete deploy <span class="token variable parameter">-n</span> ambassador traffic-manager </span><span class="code-line">k delete secrets sh.helm.release.v1.traffic-manager.v1 <span class="token variable parameter">-n</span> ambassador </span></code></pre></div><p>注意它并不会真正检查 pod 是否存在, 如果检查到 <code>sh.helm.release.v1.traffic-manager.v1</code> 这个 secrets 就会直接跳过安装了. 所以你要是删除了 traffic manger 的 deployment, 但是忘记删除了这个 secrets, 会导致下次连接的时候, traffic manger 不会被安装.</p><h3 id="4-调试问题"><a href="#4-调试问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4. 调试问题</h3><p>k8s 端问题查看:</p><p>先检查 pod 是不是正常:</p><p><code>k get po -n ambassador</code></p><p><code>k get deploy -n ambassador</code></p><p>查看 pod 日志:</p><p><code>k logs -n ambassador -f traffic-manager</code></p><h3 id="5-编译和构建容器镜像"><a href="#5-编译和构建容器镜像" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>5. 编译和构建容器镜像</h3><p>traffic manager 的版本一定要匹配客户端的版本.</p><p>对于 nightly 版本, 其形式如 <code>v2.5.4-2-g8ccf3c9d</code></p><p>对于正式版, 其形式如 <code>v2.5.3</code></p><p>不同版本不能连接, 会提示错误. 即使是客户端, 不同版本的 daemon 也是不兼容的, 如:</p><blockquote><p>version mismatch. Client v2.5.3 != User Daemon v2.5.4-2-g8ccf3c9d, please run &#x27;telepresence quit -u&#x27; and reconnect</p></blockquote><p>计算当前 nightly 版本号: <code>git describe --tags --match=&#x27;v*&#x27;</code></p><p>build 的时候,必须通过 env 指定 <code>TELEPRESENCE_VERSION</code>, 不然 <code>Makefile</code> 会自动运行 <code>go run build/genversion.go</code> 生成一个带 unix timestamp 的版本号,这样客户端和 agent docker image 的版本号便没办法对应上了。</p><p>同时还要指定 <code>TELEPRESENCE_REGISTRY</code> , 这个主要是在构建时打docker tag用的,主要用于 docker push, 真正程序运行的时候,取的还是 <code>env:&quot;TELEPRESENCE_REGISTRY,default=docker.io/datawire&quot;</code> 因此,如果要防止客户端安装官方镜像, 这一行硬编码的代码必须修改.</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"># 构建本地bin和容器镜像并 push<span class="token operator">:</span> </span><span class="code-line">make build image push<span class="token operator">-</span>image <span class="token constant">TELEPRESENCE_VERSION</span><span class="token operator">=</span>v2<span class="token punctuation">.</span><span class="token number">5.4</span> <span class="token constant">TELEPRESENCE_REGISTRY</span><span class="token operator">=</span>docker<span class="token punctuation">.</span><span class="token property-access">io</span><span class="token operator">/</span>ttys3 </span><span class="code-line"> </span><span class="code-line"># 只构建本地bin </span><span class="code-line">make build <span class="token constant">TELEPRESENCE_VERSION</span><span class="token operator">=</span>v2<span class="token punctuation">.</span><span class="token number">5.4</span> <span class="token constant">TELEPRESENCE_REGISTRY</span><span class="token operator">=</span>docker<span class="token punctuation">.</span><span class="token property-access">io</span><span class="token operator">/</span>ttys3 </span></code></pre></div><h3 id="6-突然无法访问的rust文档站点docsrs"><a href="#6-突然无法访问的rust文档站点docsrs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>6. 突然无法访问的Rust文档站点docs.rs</h3><p>连接 telepresence后, 发现 <code>https://docs.rs/</code> 怎么也打不开了. <code>dig docs.rs</code> 发现超时, 并没有解析成功.</p><p>然后我想到了原因, 有人在集群里创建了一个名为 <code>rs</code> 的命名空间, 连接 telepresence后, 导致所有 <code>.rs</code> 域名都无法解析了(除了 k8s 集群里面的 ).</p><p>经过查看源码, 老灯发现可以通过patch <code>updateLinkDomains</code> 这个方法搞定. 思路就是, 如果一个命名空间, 是ICANN 管理的通用 TLD 后缀, 则直接 skip 它, 不设置.</p><p>直接修改 telepresence 源码然后自己编译客户端即可:</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">diff --git a/pkg/client/rootd/dns/resolved_linux.go b/pkg/client/rootd/dns/resolved_linux.go </span><span class="code-line">index b2e8897bbeb5405170359f5318a7ae40dfc6e949..d90c2735ef9d4d421738fea533f7bfb244172b61 100644 </span><span class="code-line deleted"><span class="token coord">--- a/pkg/client/rootd/dns/resolved_linux.go</span> </span><span class="code-line inserted"><span class="token coord">+++ b/pkg/client/rootd/dns/resolved_linux.go</span> </span><span class="code-line">@@ -13,6 +13,7 @@ import ( </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> &quot;github.com/datawire/dlib/dtime&quot; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &quot;github.com/telepresenceio/telepresence/v2/pkg/client/rootd/dbus&quot; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &quot;github.com/telepresenceio/telepresence/v2/pkg/vif&quot; </span></span></span><span class="code-line inserted"><span class="token unchanged"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> &quot;golang.org/x/net/publicsuffix&quot; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">func (s *Server) tryResolveD(c context.Context, dev *vif.Device, configureDNS func(net.IP, *net.UDPAddr)) error { </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>@@ -102,28 +103,36 @@ func (s *Server) tryResolveD(c context.Context, dev *vif.Device, configureDNS fu </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">func (s *Server) updateLinkDomains(c context.Context, paths []string, dev *vif.Device) error { </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> namespaces := make(map[string]struct{}) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> search := make([]string, 0) </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> for i, path := range paths { </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> pathsFiltered := make([]string, 0) </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> for _, path := range paths { </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> if strings.ContainsRune(path, &#x27;.&#x27;) { </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> search = append(search, path) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> } else { </span></span></span><span class="code-line inserted"><span class="token unchanged"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> // skip namespace which conflict with eTLD like `im`, `rs` to avoid pollute client normal DNS query </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> if eTLD, icann := publicsuffix.PublicSuffix(path); icann &amp;&amp; path == eTLD { </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> dlog.Infof(c, &quot;Skip set Link domains on device %q for [%s] due to conflict with ICANN eTLD [%s]&quot;, </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> dev.Name(), path, eTLD) </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> continue </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> } </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> namespaces[path] = struct{}{} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> // Turn namespace into a route </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> paths[i] = &quot;~&quot; + path </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> // paths[i] = &quot;~&quot; + path </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> pathsFiltered = append(pathsFiltered, &quot;~&quot;+path) </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> } </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> } </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> for _, sfx := range s.config.IncludeSuffixes { </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> paths = append(paths, &quot;~&quot;+strings.TrimPrefix(sfx, &quot;.&quot;)) </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> pathsFiltered = append(pathsFiltered, &quot;~&quot;+strings.TrimPrefix(sfx, &quot;.&quot;)) </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> } </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> paths = append(paths, &quot;~&quot;+s.clusterDomain) </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> pathsFiltered = append(pathsFiltered, &quot;~&quot;+s.clusterDomain) </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> namespaces[tel2SubDomain] = struct{}{} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> s.domainsLock.Lock() </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> s.namespaces = namespaces </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> s.search = search </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> s.domainsLock.Unlock() </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> if err := dbus.SetLinkDomains(dcontext.HardContext(c), int(dev.Index()), paths...); err != nil { </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> if err := dbus.SetLinkDomains(dcontext.HardContext(c), int(dev.Index()), pathsFiltered...); err != nil { </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> return fmt.Errorf(&quot;failed to set link domains on %q: %w&quot;, dev.Name(), err) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> } </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> dlog.Debugf(c, &quot;Link domains on device %q set to [%s]&quot;, dev.Name(), strings.Join(paths, &quot;,&quot;)) </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> dlog.Debugf(c, &quot;Link domains on device %q set to [%s]&quot;, dev.Name(), strings.Join(pathsFiltered, &quot;,&quot;)) </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> return nil </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">} </span></span></span></code></pre></div><p>注意: telepresence 的 <code>exclude-suffixes</code> 选项并不能解决我们这里的问题.</p><p><a href="https://www.telepresence.io/docs/latest/reference/config/#dns">https://www.telepresence.io/docs/latest/reference/config/#dns</a></p><p>其默认值为 <code>[&quot;.arpa&quot;, &quot;.com&quot;, &quot;.io&quot;, &quot;.net&quot;, &quot;.org&quot;, &quot;.ru&quot;]</code></p><blockquote><p><code>exclude-suffixes</code> Suffixes for which the DNS resolver will <strong>always fail</strong> (or fallback in case of the overriding resolver)</p></blockquote><p>由于我们用的都是基于systemd-resolved 的 resover, 因此, 如果把 `.rs` 加入这个列表, 则会导致 `.rs` 域名总是解析失败(NXDomain)</p><p>所以其实这个默认列表也是有问题的, 为什么默认有 `.com`, 而 `google.com` 不会解析失败呢? 那是因为我们没有名为 `com` 的命名空间. 所以, 假设你有名为 `com` 的命名空间, 就要小心了.</p><h3 id="7-dns-解析特别慢或超时"><a href="#7-dns-解析特别慢或超时" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>7. DNS 解析特别慢或超时</h3><p>我们同时在开发和测试环境部署了 telepresence (traffic manager).</p><p>使用中发现, 测试环境丝滑无比, 开发环境总是 DNS 解析超时.</p><p>通过查看log可发现类似日志:</p><blockquote><p>LookupHost: lookup kubernetes.default on 10.0.165.145:53: dial udp 10.0.165.145:53: i/o timeout</p></blockquote><p>暂时没排查出什么原因, 大概率是 coredns 出问题了.</p><p>干了 coredns pod 之后, 等 coredns pod 重新 ruuning 了, 再把 traffic manager 的 pod干了,</p><p>重新测试, 发现正常了.</p><h2 id="8-某些网段或ip的流量不想走-tel0-tun-出去"><a href="#8-某些网段或ip的流量不想走-tel0-tun-出去" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>8. 某些网段或IP的流量不想走 tel0 tun 出去</h2><p>这个也是通过k8s 扩展配置实现的, 之所以放在这里, 我想 telepresence 是考虑到对于不同人集群, 可以方便支持不同的配置.</p><p>修改 <code>~/.kube/config</code> 文件, 增加配置到 <code>never-proxy</code> 数组即可, 如要将 10.10.8.9 单个IP排除:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token operator">-</span> cluster<span class="token operator">:</span> </span><span class="code-line"> certificate<span class="token operator">-</span>authority<span class="token operator">-</span>data<span class="token operator">:</span> xxxxxx </span><span class="code-line"> <span class="token literal-property property">server</span><span class="token operator">:</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>example<span class="token punctuation">.</span><span class="token property-access">com</span> </span><span class="code-line"> <span class="token literal-property property">extensions</span><span class="token operator">:</span> </span><span class="code-line"> <span class="token operator">-</span> name<span class="token operator">:</span> telepresence<span class="token punctuation">.</span><span class="token property-access">io</span> </span><span class="code-line"> <span class="token literal-property property">extension</span><span class="token operator">:</span> </span><span class="code-line"> never<span class="token operator">-</span>proxy<span class="token operator">:</span> </span><span class="code-line"> <span class="token operator">-</span> <span class="token number">10.10</span><span class="token number">.8</span><span class="token number">.9</span><span class="token operator">/</span><span class="token number">32</span> </span><span class="code-line"> <span class="token literal-property property">name</span><span class="token operator">:</span> cluster<span class="token operator">-</span><span class="token number">001</span> </span></code></pre></div><p>k8s 集群 api server 的 IP telepresence是会默认排除的(通过 <code>telepresence status </code>你可以看到这一点), 除此之外 , 如果你有些外部服务, 因为网段跟 k8s cluster IP 段重合, 导致流量错误地走了 tel0 tun 设备, 就可以通过这个配置来修正.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p>在本地开发和调试服务 <a href="https://kubernetes.io/zh/docs/tasks/debug-application-cluster/local-debugging/">https://kubernetes.io/zh/docs/tasks/debug-application-cluster/local-debugging/</a></p><p><a href="https://www.telepresence.io/docs/latest/reference/routing/">https://www.telepresence.io/docs/latest/reference/routing/</a></p><p><a href="https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html">https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html</a></p><p><a href="https://www.telepresence.io/docs/latest/reference/config/#dns">https://www.telepresence.io/docs/latest/reference/config/#dns</a></p><p><a href="https://www.getambassador.io/docs/telepresence/latest/howtos/intercepts/">https://www.getambassador.io/docs/telepresence/latest/howtos/intercepts/</a></p><p><a href="https://github.com/telepresenceio/telepresence/tree/release/v2">https://github.com/telepresenceio/telepresence/tree/release/v2</a></p><p><a href="https://www.getambassador.io/docs/telepresence/latest/quick-start/qs-go/">https://www.getambassador.io/docs/telepresence/latest/quick-start/qs-go/</a></p> Thu, 17 Mar 2022 15:34:46 GMT ttyS3 k8stelepresencetun https://ttys3.dev/blog/confusing-golang-compiler-optimization Golang编译器优化迷之操作 https://ttys3.dev/blog/confusing-golang-compiler-optimization <h2 id="简单的代码-问题不简单"><a href="#简单的代码-问题不简单" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>简单的代码, 问题不简单</h2><p>今天有人发了段代码给我, 然后问输出结果是什么?</p><p>这段代码看上去非常简单, 但是确是很有迷惑性.</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// a.go</span> </span><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;fmt&quot;</span> </span><span class="code-line"> <span class="token string">&quot;time&quot;</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">var</span> x <span class="token builtin">int64</span> <span class="token operator">=</span> <span class="token number">0</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> i<span class="token operator">%</span><span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">2</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">go</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">{</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">&quot;x=%v\n&quot;</span><span class="token punctuation">,</span> x<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token comment">// x=0</span> </span><span class="code-line"> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>答案是: 不断地输出 <code>x=0</code></p><p>tested under Go 1.17 / Go 1.18</p><p>为什么是 0 ? 刚开始老灯也有疑问. 查看了汇编之后, 才确定是编译器优化在搞鬼.</p><p>假设文件名为 a.go, 我们直接执行 <code>go run a.go</code> 结果就是输出0</p><p>我们稍微改一下, 就在 for 里面加个小 sleep (sleep 多久不重要):</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// b.go</span> </span><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;fmt&quot;</span> </span><span class="code-line"> <span class="token string">&quot;time&quot;</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">var</span> x <span class="token builtin">int64</span> <span class="token operator">=</span> <span class="token number">0</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> </span><span class="code-line"> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> i<span class="token operator">%</span><span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">2</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">go</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">{</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">&quot;x=%v\n&quot;</span><span class="token punctuation">,</span> x<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token comment">// x=0</span> </span><span class="code-line"> <span class="token comment">// x=2</span> </span><span class="code-line"> <span class="token comment">// x=1</span> </span><span class="code-line"> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>这个新加的 <code>time.Sleep(time.Millisecond * 16)</code> 会导致编译器不再将这个函数对 <code>x</code> 的赋值操作优化掉.</p><p>我们继续变一下, 这将主要是让这个函数有条件返回, 同样的, 编译器不会再优化掉对 <code>x</code> 的赋值操作:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// c.go</span> </span><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;fmt&quot;</span> </span><span class="code-line"> <span class="token string">&quot;time&quot;</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">var</span> x <span class="token builtin">int64</span> <span class="token operator">=</span> <span class="token number">0</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">10000000001</span><span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> i<span class="token operator">%</span><span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">2</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">go</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">{</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">&quot;x=%v\n&quot;</span><span class="token punctuation">,</span> x<span class="token punctuation">)</span> </span><span class="code-line"><span class="token comment">// x=0</span> </span><span class="code-line"><span class="token comment">// x=1</span> </span><span class="code-line"><span class="token comment">// x=1</span> </span><span class="code-line"><span class="token comment">// x=1</span> </span><span class="code-line"><span class="token comment">// x=2</span> </span><span class="code-line"><span class="token comment">// x=1</span> </span><span class="code-line"> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>接着, 我们再变一下, 没错, 我们把 <code>for</code> 移到后面了, 结果会是输出 2 吗?</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// d.go</span> </span><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;fmt&quot;</span> </span><span class="code-line"> <span class="token string">&quot;time&quot;</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">var</span> x <span class="token builtin">int64</span> <span class="token operator">=</span> <span class="token number">0</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">var</span> i <span class="token builtin">int</span> </span><span class="code-line"> <span class="token keyword">if</span> i<span class="token operator">%</span><span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">2</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">go</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">{</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">&quot;x=%v\n&quot;</span><span class="token punctuation">,</span> x<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token comment">// x=0</span> </span><span class="code-line"> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>答案是: 不会, 结果还是输出 <code>0</code></p><p>目前的测试结果看来, 只要这里是个死循环, 并且里面没有加 sleep 类的操作, 照样会被优化.</p><p>我们再来一个变种:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// e.go</span> </span><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;fmt&quot;</span> </span><span class="code-line"> <span class="token string">&quot;time&quot;</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">var</span> x <span class="token builtin">int64</span> <span class="token operator">=</span> <span class="token number">0</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// time.Sleep(time.Millisecond * 10)</span> </span><span class="code-line"> <span class="token keyword">if</span> i<span class="token operator">%</span><span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">2</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">go</span> <span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">{</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">&quot;x=%v\n&quot;</span><span class="token punctuation">,</span> x<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token comment">// x=0</span> </span><span class="code-line"> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h2 id="这个问题和多线程访问变量有关吗"><a href="#这个问题和多线程访问变量有关吗" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>这个问题和多线程访问变量有关吗?</h2><p>完全无关. 有人评论说, 你这个代码, 不用多线程你两个死循环完全跑不了.</p><p>所以, 我这里增加了这段, 用于测试验证, 和多线程无关. 本质上是编译器优化, 跟多线程不多线程没有任何关系.</p><p>我完全可以去掉多线程 <code>go storeFunc()</code> 修改成 <code>storeFunc()</code> 即可 (不要说你这第二个loop没机会运行, 这里只是为了说明, 与多线程没有关系), 生成的优化代码是完全一样的:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// a.go</span> </span><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;fmt&quot;</span> </span><span class="code-line"> <span class="token string">&quot;time&quot;</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">var</span> x <span class="token builtin">int64</span> <span class="token operator">=</span> <span class="token number">0</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> i<span class="token operator">%</span><span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">2</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">storeFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">{</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">&quot;x=%v\n&quot;</span><span class="token punctuation">,</span> x<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token comment">// x=0</span> </span><span class="code-line"> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Millisecond <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>生成的汇编是一模一样的:</p><div class="relative"><pre><code class="code-highlight language-asm"><span class="code-line">&quot;&quot;.storeFunc STEXT nosplit size=3 args=0x0 locals=0x0 funcid=0x0 align=0x0 </span><span class="code-line"> 0x0000 00000 (a.go:11) TEXT &quot;&quot;.storeFunc(SB), NOSPLIT|ABIInternal, $0-0 </span><span class="code-line"> 0x0000 00000 (a.go:11) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) </span><span class="code-line"> 0x0000 00000 (a.go:11) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) </span><span class="code-line"> 0x0000 00000 (a.go:12) XCHGL AX, AX </span><span class="code-line"> 0x0001 00001 (a.go:1) JMP 0 </span><span class="code-line"> 0x0000 90 eb fd </span></code></pre></div><p>当然, 正常开发中没人会这样写代码.</p><p>同样, 正常开发的时候, 我们多线程读写同一个内存, 一般都会加锁, 为了避免 CPU 方面的优化, 我们还可能会采用原子操作 (go <code>atomic</code> pkg).</p><h2 id="有没有办法禁止这种优化"><a href="#有没有办法禁止这种优化" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>有没有办法禁止这种优化?</h2><p>当然是有的, 编译的时候加 <code>-gcflags &#x27;-N&#x27;</code> 即可. (还有个 <code>-l</code> 表示 <code>noinline</code> , 由于这里我们的讨论不涉及inline优化, 因此这里不讨论这个参数). 禁止优化执行的结果是预期的:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">go run <span class="token variable parameter">-gcflags</span> <span class="token string">&#x27;-N&#x27;</span> a.go </span><span class="code-line"> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">0</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">2</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">2</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">2</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">2</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">x</span><span class="token operator">=</span><span class="token number">1</span> </span></code></pre></div><p>ps: 构建时用 <code>go build -gcflags &#x27;-N&#x27;</code>即可.</p><p>我们看下禁止优化(<code>-N</code>)后的Go 汇编代码( 我们这里只关注 <code>func storeFunc()</code> 这个函数的):</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">go tool compile <span class="token variable parameter">-N</span> <span class="token variable parameter">-S</span> a.go </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-asm"><span class="code-line"> TEXT &quot;&quot;.storeFunc(SB), NOSPLIT|ABIInternal, $16-0 </span><span class="code-line"> SUBQ $16, SP </span><span class="code-line"> MOVQ BP, 8(SP) </span><span class="code-line"> LEAQ 8(SP), BP </span><span class="code-line"> FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) </span><span class="code-line"> FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) </span><span class="code-line"> MOVQ $0, &quot;&quot;.i(SP) </span><span class="code-line"> JMP storeFunc_pc24 </span><span class="code-line">storeFunc_pc24: </span><span class="code-line"> JMP storeFunc_pc26 </span><span class="code-line">storeFunc_pc26: </span><span class="code-line"> MOVQ &quot;&quot;.i(SP), AX </span><span class="code-line"> BTL $0, AX </span><span class="code-line"> JCC storeFunc_pc38 </span><span class="code-line"> JMP storeFunc_pc51 </span><span class="code-line">storeFunc_pc38: </span><span class="code-line"> MOVQ $2, &quot;&quot;.x(SB) </span><span class="code-line"> JMP storeFunc_pc66 </span><span class="code-line">storeFunc_pc51: </span><span class="code-line"> MOVQ $1, &quot;&quot;.x(SB) </span><span class="code-line"> NOP </span><span class="code-line"> JMP storeFunc_pc66 </span><span class="code-line">storeFunc_pc66: </span><span class="code-line"> JMP storeFunc_pc68 </span><span class="code-line">storeFunc_pc68: </span><span class="code-line"> MOVQ &quot;&quot;.i(SP), AX </span><span class="code-line"> INCQ AX </span><span class="code-line"> MOVQ AX, &quot;&quot;.i(SP) </span><span class="code-line"> JMP storeFunc_pc24 </span></code></pre></div><p><code>TEXT &quot;&quot;.storeFunc(SB), NOSPLIT|ABIInternal, $16-0</code> 表示 <code>storeFunc</code> 函数开始.</p><p><code>MOVQ $0, &quot;&quot;.i(SP)</code> 把 0 丢给 i</p><p><code>MOVQ &quot;&quot;.i(SP), AX</code> 把 i 丢给 AX</p><p><code>BTL $0, AX</code>, <code>BT</code> 是 Bit Test 的意思, 位检测指令. 结果会影响 CF (carry flag), 因此后面用 JCC 判断. 取第0个 bit 丢给 CF</p><p>关于 BT:</p><blockquote><p>Selects the bit in a bit string (specified with the first operand, called the bit base) at the bit-position designated by the bit offset (specified by the second operand) and stores the value of the bit in the CF flag. The bit base operand can be a register or a memory location; the bit offset operand can be a register or an immediate value.</p></blockquote><p><code>CF ← Bit(BitBase, BitOffset);</code></p><p>注意, 这段描述是针对 Intel asm的, GCC 使用 AT&amp;T 风格的 asm, 因此参数是反的. 另外, AT&amp;T 语法 Immediate values prefixed with a <code>$</code>, registers prefixed with a <code>%</code> 比如 AT&amp;T <code>movl $5, %eax</code>, Intel 则是 <code>mov eax, 5</code>, 我们教科书里面基本上介绍 Intel asm, 包括单片机那些. 老灯也是看不太习惯 AT&amp;T 语法, 可能 Intel 先入为主了吧.</p><p>ref <a href="https://en.wikipedia.org/wiki/X86_assembly_language#Syntax">https://en.wikipedia.org/wiki/X86_assembly_language#Syntax</a></p><p><code>JCC storeFunc_pc38</code>, AX 最低位是 0 则跳到 storeFunc_pc38, 这里怎么直接是 <code>JCC</code> ? 老灯觉得这里应该是 <code>JNC</code> 或 <code>JAE</code> ? 关于这个, 后面老灯再说.</p><p><code>MOVQ $2, &quot;&quot;.x(SB)</code> 即把 2 丢给 x 啦.</p><p>否则, JCC 没跳, 则 <code>MOVQ $1, &quot;&quot;.x(SB)</code>, 把 1 丢给 x</p><p>此即:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token keyword">if</span> i<span class="token operator">%</span><span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">2</span> </span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> x <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>最后 <code>JMP storeFunc_pc24</code> 又跳回去了. 无限循环.</p><p>好了, 我们再看一下被优化过的 <code>storeFunc</code> 函数长啥样:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">go tool compile <span class="token variable parameter">-S</span> a.go </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-asm"><span class="code-line">storeFunc_pc0: </span><span class="code-line"> TEXT &quot;&quot;.storeFunc(SB), NOSPLIT|ABIInternal, $0-0 </span><span class="code-line"> FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) </span><span class="code-line"> FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) </span><span class="code-line"> XCHGL AX, AX </span><span class="code-line"> JMP storeFunc_pc0 </span></code></pre></div><p>没错, 只有一个 <code>XCHGL AX, AX</code> 指令, 然后就是 <code>JMP storeFunc_pc0</code> 死循环. 整个指令完全把对 <code>x</code> 的赋值操作优化没了.</p><h2 id="go-汇编迷一样的条件跳转语句"><a href="#go-汇编迷一样的条件跳转语句" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Go 汇编迷一样的条件跳转语句</h2><p>Go 汇编 里面的条件跳转语句, 对于熟悉 Intel x86 语法的人来说, 也是很迷的. 老灯在这找到了一个<a href="https://stackoverflow.com/a/30146643">对应表</a>: 实际上应该是结合 <a href="https://github.com/golang/go/blob/ed4db861182456a63b7d837780c146d4e58e63d8/src/cmd/asm/internal/arch/arch.go#L128">https://github.com/golang/go/blob/ed4db861182456a63b7d837780c146d4e58e63d8/src/cmd/asm/internal/arch/arch.go#L128</a> 和 x86 指令总结的.</p><table><thead><tr><th>Go</th><th>x86</th></tr></thead><tbody><tr><td>JCC</td><td>JAE</td></tr><tr><td>JCS</td><td>JB</td></tr><tr><td>JCXZL</td><td>JECXZ</td></tr><tr><td>JEQ</td><td>JE,JZ</td></tr><tr><td>JGE</td><td>JGE</td></tr><tr><td>JGT</td><td>JG</td></tr><tr><td>JHI</td><td>JA</td></tr><tr><td>JLE</td><td>JLE</td></tr><tr><td>JLS</td><td>JBE</td></tr><tr><td>JLT</td><td>JL</td></tr><tr><td>JMI</td><td>JS</td></tr><tr><td>JNE</td><td>JNE, JNZ</td></tr><tr><td>JOC</td><td>JNO</td></tr><tr><td>JOS</td><td>JO</td></tr><tr><td>JPC</td><td>JNP, JPO</td></tr><tr><td>JPL</td><td>JNS</td></tr><tr><td>JPS</td><td>JP, JPE</td></tr></tbody></table><h2 id="开启优化-怎么确保-x-的值被设置"><a href="#开启优化-怎么确保-x-的值被设置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>开启优化, 怎么确保 x 的值被设置?</h2><p>答案当然是用 atomic 操作啦. <a href="https://pkg.go.dev/sync/atomic">https://pkg.go.dev/sync/atomic</a></p><p>可以用 LoadInt64 和 StoreInt64 读写.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://dave.cheney.net/2020/04/25/inlining-optimisations-in-go">https://dave.cheney.net/2020/04/25/inlining-optimisations-in-go</a></p><p><a href="https://dave.cheney.net/2018/01/08/gos-hidden-pragmas">https://dave.cheney.net/2018/01/08/gos-hidden-pragmas</a></p><p><a href="https://en.wikipedia.org/wiki/X86_assembly_language#Syntax">https://en.wikipedia.org/wiki/X86_assembly_language#Syntax</a></p><p>A Quick Guide to Go&#x27;s Assembler <a href="https://go.dev/doc/asm">https://go.dev/doc/asm</a></p><p><a href="https://pkg.go.dev/sync/atomic#LoadInt64">https://pkg.go.dev/sync/atomic#LoadInt64</a></p><p><a href="https://godbolt.org/">https://godbolt.org/</a></p><p><a href="https://github.com/teh-cmc/go-internals/blob/master/chapter1_assembly_primer/README.md">https://github.com/teh-cmc/go-internals/blob/master/chapter1_assembly_primer/README.md</a></p><p><a href="https://go.dev/doc/asm">https://go.dev/doc/asm</a></p> Wed, 16 Mar 2022 19:14:43 GMT ttyS3 golangcomplierasmoptimization https://ttys3.dev/blog/archlinux-mpv-undefined-symbol-vkcreatewaylandsurfacekhr ArchLinux 下 mpv: undefined symbol: vkCreateWaylandSurfaceKHR 问题解决 https://ttys3.dev/blog/archlinux-mpv-undefined-symbol-vkcreatewaylandsurfacekhr <h2 id="问题现象"><a href="#问题现象" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>问题现象</h2><ol><li>在Gnome Terminal 直接执行 <code>mpv filename.mp4</code> 报错:</li></ol><blockquote><p>mpv: symbol lookup error: mpv: undefined symbol: vkCreateWaylandSurfaceKHR</p></blockquote><ol start="2"><li>使用 smplayer 打开同样的文件, 也是同样的报错.</li></ol><h2 id="解决办法"><a href="#解决办法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>解决办法</h2><p>这个解决办法很简单.</p><p>但是我要说的是, 这个问题其实我花了很长时间才解决, 并且不是我自己想到的.</p><p>产生这个问题的时候, 一般是更新了某些软件之后.</p><p>当时我想, 这个是视频相关的, 可能跟显卡驱动相关. 但是后面发现, 即使重启系统, 或者重新编译mpv, 这个问题还是不能解决. 但是有时候重启系统后又能成功打开文件.</p><p>报错是 <code>undefined symbol: vkCreateWaylandSurfaceKHR</code> , 但是其实这个问题跟 wayland 无关, 因为我用的是 N 卡 + X11.</p><p>搜索了一下, 得知 <code>vkCreateWaylandSurfaceKHR</code> 这个符号来自 <code>libvulkan</code>, 但是本机有正常安装 <code>libvulkan</code>.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ paru <span class="token variable parameter">-Ss</span> libvulkan <span class="token operator">|</span> rg installed </span><span class="code-line">extra/vulkan-icd-loader <span class="token number">1.2</span>.203-1 <span class="token punctuation">[</span>0B <span class="token number">481</span>.45KiB<span class="token punctuation">]</span> <span class="token punctuation">[</span>Installed<span class="token punctuation">]</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">ls</span> <span class="token variable parameter">-l</span> /usr/lib/libvulkan* </span><span class="code-line">lrwxrwxrwx root root <span class="token number">14</span> B Fri Jan <span class="token number">21</span> <span class="token number">23</span>:07:49 <span class="token number">2022</span>  /usr/lib/libvulkan.so ⇒ libvulkan.so.1 </span><span class="code-line">lrwxrwxrwx root root <span class="token number">20</span> B Fri Jan <span class="token number">21</span> <span class="token number">23</span>:07:49 <span class="token number">2022</span>  /usr/lib/libvulkan.so.1 ⇒ libvulkan.so.1.2.203 </span><span class="code-line">.rwxr-xr-x root root <span class="token number">470</span> KB Fri Jan <span class="token number">21</span> <span class="token number">23</span>:07:49 <span class="token number">2022</span>  /usr/lib/libvulkan.so.1.2.203 </span><span class="code-line">.rwxr-xr-x root root <span class="token number">11</span> MB Sat Mar <span class="token number">5</span> 08:14:57 <span class="token number">2022</span>  /usr/lib/libvulkan_intel.so </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"> ❯ strings /usr/lib/libvulkan.so.1 <span class="token operator">|</span> rg vkCreateWaylandSurfaceKHR </span><span class="code-line">vkCreateWaylandSurfaceKHR </span><span class="code-line">vkCreateWaylandSurfaceKHR </span><span class="code-line">VK_KHR_wayland_surface extension not enabled. vkCreateWaylandSurfaceKHR not executed<span class="token operator">!</span> </span><span class="code-line">vkCreateWaylandSurfaceKHR: Invalid instance <span class="token punctuation">[</span>VUID-vkCreateWaylandSurfaceKHR-instance-parameter<span class="token punctuation">]</span> </span></code></pre></div><ol><li>重新编译 mpv 不能解决</li><li>问题只在有时候出现(条件不明确)</li><li>undefined symbol 这种错误按以往的经常是特别容易解决的, 安装好对应的lib就好了, 但是现在的情况是, 有正确的 lib 安装了, 依旧报错</li></ol><p>所以, 一时间找不到思路了.</p><p>直到有一天, 通过搜索看到了<a href="https://www.reddit.com/r/mpv/comments/ry9sgi/i_keep_getting_this_error_when_opening_mpv_on/">reddit 上一个回答</a>. 终于找到了正确的答案.</p><blockquote><p>This is because chrome provides a broken copy of vulkan which is loaded while it tries to execute mpv. The fix is to make a little wrapper at <code>/usr/local/bin/mpv</code> that preloads the system version of vulkan:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token important shebang">#!/bin/sh</span> </span><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">LD_PRELOAD</span><span class="token operator">=</span>/usr/lib/libvulkan.so.1 </span><span class="code-line"><span class="token class-name builtin">exec</span> /usr/bin/mpv <span class="token string">&quot;<span class="token variable">$@</span>&quot;</span> </span></code></pre></div></blockquote><p>简单来说就是, Google Chrome 自带了一个 没有 <code>vkCreateWaylandSurfaceKHR</code> 符号的 libvulkan.so, 并且优先于系统的 libvulkan.so 加载了.</p><p>解决办法是通过一个脚本wrapper来启动mpv. 然后设置 smplayer 调用这个wrapper.</p><div><img alt="" src="https://ttys3.dev/static/assets/smplayer-mpv-wrapper-2022-03-06_23-20-Y5ZYYDCU.png" width="1415" height="751"/></div><h2 id="未解之迷"><a href="#未解之迷" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>未解之迷</h2><p>这个方法可以解决问题, 但是有一点老灯还没想明白.</p><p>为什么 Chrome 会影响整个系统的 <code>LD_LIBRARY_PATH</code> 环境变量 ? 一般来说, 通过一个 shell 脚本设置的变量, 不会影响其它 shell 的.</p><p>通过 kitty 执行 <code>/usr/bin/env | rg LD_LIBRARY_PATH</code> 无结果.</p><p>在 kitty 下面:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ ldd /usr/bin/mpv <span class="token operator">|</span> rg libvulkan.so.1 </span><span class="code-line"> libvulkan.so.1 <span class="token operator">=</span><span class="token operator">&gt;</span> /usr/lib/libvulkan.so.1 <span class="token punctuation">(</span>0x00007fa58880a000<span class="token punctuation">)</span> </span></code></pre></div><p>唯独在 gnome terminal 下得到的结果是 <code>LD_LIBRARY_PATH=/opt/google/chrome:/opt/google/chrome/lib</code></p><p>自然而然, 加载的是 Google 的 <code>/opt/google/chrome/libvulkan.so.1</code></p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ /usr/bin/env <span class="token operator">|</span> rg LD_LIBRARY_PATH </span><span class="code-line"><span class="token variable assign-left">LD_LIBRARY_PATH</span><span class="token operator">=</span>/opt/google/chrome:/opt/google/chrome/lib </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">❯ ldd /usr/bin/mpv <span class="token operator">|</span> rg libvulkan.so.1 </span><span class="code-line"> libvulkan.so.1 <span class="token operator">=</span><span class="token operator">&gt;</span> /opt/google/chrome/libvulkan.so.1 <span class="token punctuation">(</span>0x00007fd41628b000<span class="token punctuation">)</span> </span></code></pre></div><p>所以, 现在的问题是, 为什么Chrome 启动脚本里的 LD_LIBRARY_PATH 会对 Gome Terminal 或者 smplayer 有效,</p><p>而在 kitty 等其它终端里面却获取不到?</p><p>尝试重启一次系统, 这次发现, 连 gnome terminal 下也没有 LD_LIBRARY_PATH 这个值了.</p><p>所以, 当gnome terminal 下能取到 LD_LIBRARY_PATH 这个值的时候, 发生了什么?</p><p>由于无法复现, 这里老灯也已经无法继续探索了.</p><p>/usr/lib/gnome-terminal-server (gnome terminal实际干活的进程) 和 smplayer 获取环境变量的方式, 和 kitty 有什么不同?</p><p>是否跟安装了 chrome-gnome-shell 有关系?</p><p>在 Linux 下面的 Google Chrome 启动实际上是通过 google-chrome 这个shell 脚本启动的 (edge 也一样, 只是重命名为了 microsoft-edge ), 在 ArchLinux 下这个路径是 /opt/google/chrome/google-chrome</p><p>其内容如下:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token comment hashbang">#!/bin/bash</span> </span><span class="code-line"># </span><span class="code-line"># <span class="token function"><span class="token maybe-class-name">Copyright</span></span> <span class="token punctuation">(</span>c<span class="token punctuation">)</span> <span class="token number">2011</span> <span class="token maybe-class-name">The</span> <span class="token maybe-class-name">Chromium</span> <span class="token maybe-class-name">Authors</span><span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">All</span></span> rights reserved<span class="token punctuation">.</span> </span><span class="code-line"># <span class="token maybe-class-name">Use</span> <span class="token keyword">of</span> <span class="token keyword">this</span> source code is governed by a <span class="token constant">BSD</span><span class="token operator">-</span>style license that can be </span><span class="code-line"># found <span class="token keyword">in</span> the <span class="token constant">LICENSE</span> file<span class="token punctuation">.</span> </span><span class="code-line"> </span><span class="code-line"># <span class="token maybe-class-name">Let</span> the wrapped binary know that it has been run through the wrapper<span class="token punctuation">.</span> </span><span class="code-line"><span class="token keyword module">export</span> <span class="token constant">CHROME_WRAPPER</span><span class="token operator">=</span><span class="token string">&quot;`readlink -f &quot;</span>$0<span class="token string">&quot;`&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token constant">HERE</span><span class="token operator">=</span><span class="token string">&quot;`dirname &quot;</span>$<span class="token constant">CHROME_WRAPPER</span><span class="token string">&quot;`&quot;</span> </span><span class="code-line"> </span><span class="code-line"># <span class="token maybe-class-name">We</span> include some xdg utilities next to the binary<span class="token punctuation">,</span> and we want to prefer them </span><span class="code-line"># over the system versions when we know the system versions are very old<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">We</span></span> </span><span class="code-line"># detect whether the system xdg utilities are sufficiently <span class="token keyword">new</span> <span class="token class-name">to</span> be likely to </span><span class="code-line"># work <span class="token keyword control-flow">for</span> us by looking <span class="token keyword control-flow">for</span> xdg<span class="token operator">-</span>settings<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">If</span></span> we find it<span class="token punctuation">,</span> we leave $<span class="token constant">PATH</span> alone<span class="token punctuation">,</span> </span><span class="code-line"># so that the system xdg <span class="token function">utilities</span> <span class="token punctuation">(</span>including any distro patches<span class="token punctuation">)</span> will be used<span class="token punctuation">.</span> </span><span class="code-line"><span class="token keyword control-flow">if</span> <span class="token operator">!</span> command <span class="token operator">-</span>v xdg<span class="token operator">-</span>settings <span class="token operator">&amp;</span><span class="token operator">&gt;</span> <span class="token operator">/</span>dev<span class="token operator">/</span><span class="token keyword nil null">null</span><span class="token punctuation">;</span> then </span><span class="code-line"> # <span class="token maybe-class-name">Old</span> xdg utilities<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">Prepend</span></span> $<span class="token constant">HERE</span> to $<span class="token constant">PATH</span> to use ours instead<span class="token punctuation">.</span> </span><span class="code-line"> <span class="token keyword module">export</span> <span class="token constant">PATH</span><span class="token operator">=</span><span class="token string">&quot;$HERE:$PATH&quot;</span> </span><span class="code-line"><span class="token keyword control-flow">else</span> </span><span class="code-line"> # <span class="token maybe-class-name">Use</span> system xdg utilities<span class="token punctuation">.</span> <span class="token property-access"><span class="token maybe-class-name">But</span></span> first create mimeapps<span class="token punctuation">.</span><span class="token property-access">list</span> <span class="token keyword control-flow">if</span> it doesn&#x27;t </span><span class="code-line"> # exist<span class="token punctuation">;</span> some systems have bugs <span class="token keyword">in</span> xdg<span class="token operator">-</span>mime that make it fail without it<span class="token punctuation">.</span> </span><span class="code-line"> <span class="token property-access">xdg_app_dir</span><span class="token operator">=</span><span class="token string">&quot;${XDG_DATA_HOME:-$HOME/.local/share/applications}&quot;</span> </span><span class="code-line"> mkdir <span class="token operator">-</span>p <span class="token string">&quot;$xdg_app_dir&quot;</span> </span><span class="code-line"> <span class="token punctuation">[</span> <span class="token operator">-</span>f <span class="token string">&quot;$xdg_app_dir/mimeapps.list&quot;</span> <span class="token punctuation">]</span> <span class="token operator">||</span> touch <span class="token string">&quot;$xdg_app_dir/mimeapps.list&quot;</span> </span><span class="code-line">fi </span><span class="code-line"> </span><span class="code-line"># <span class="token maybe-class-name">Always</span> use our versions <span class="token keyword">of</span> ffmpeg libs<span class="token punctuation">.</span> </span><span class="code-line"># <span class="token maybe-class-name">This</span> also makes <span class="token maybe-class-name">RPMs</span> find the compatibly<span class="token operator">-</span>named library symlinks<span class="token punctuation">.</span> </span><span class="code-line"><span class="token keyword control-flow">if</span> <span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token operator">-</span>n <span class="token string">&quot;$LD_LIBRARY_PATH&quot;</span> <span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> then </span><span class="code-line"> <span class="token constant">LD_LIBRARY_PATH</span><span class="token operator">=</span><span class="token string">&quot;$HERE:$HERE/lib:$LD_LIBRARY_PATH&quot;</span> </span><span class="code-line"><span class="token keyword control-flow">else</span> </span><span class="code-line"> <span class="token constant">LD_LIBRARY_PATH</span><span class="token operator">=</span><span class="token string">&quot;$HERE:$HERE/lib&quot;</span> </span><span class="code-line">fi </span><span class="code-line"><span class="token keyword module">export</span> <span class="token constant">LD_LIBRARY_PATH</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword module">export</span> <span class="token constant">CHROME_VERSION_EXTRA</span><span class="token operator">=</span><span class="token string">&quot;stable&quot;</span> </span><span class="code-line"> </span><span class="code-line"># <span class="token maybe-class-name">We</span> don&#x27;t want bug<span class="token operator">-</span>buddy intercepting our crashes<span class="token punctuation">.</span> <span class="token property-access">http</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>crbug<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span><span class="token number">24120</span> </span><span class="code-line"><span class="token keyword module">export</span> <span class="token constant">GNOME_DISABLE_CRASH_DIALOG</span><span class="token operator">=</span><span class="token constant">SET_BY_GOOGLE_CHROME</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"># <span class="token maybe-class-name">Sanitize</span> std<span class="token punctuation">{</span><span class="token keyword">in</span><span class="token punctuation">,</span>out<span class="token punctuation">,</span>err<span class="token punctuation">}</span> because they&#x27;ll be shared <span class="token keyword">with</span> untrusted child </span><span class="code-line"># <span class="token function">processes</span> <span class="token punctuation">(</span>http<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>crbug<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span><span class="token number">376567</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"><span class="token property-access">exec</span> <span class="token operator">&lt;</span> <span class="token operator">/</span>dev<span class="token operator">/</span><span class="token keyword nil null">null</span> </span><span class="code-line">exec <span class="token operator">&gt;</span> <span class="token operator">&gt;</span><span class="token punctuation">(</span>exec cat<span class="token punctuation">)</span> </span><span class="code-line">exec <span class="token number">2</span><span class="token operator">&gt;</span> <span class="token operator">&gt;</span><span class="token punctuation">(</span>exec cat <span class="token operator">&gt;</span><span class="token operator">&amp;</span><span class="token number">2</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"># <span class="token maybe-class-name">Note</span><span class="token operator">:</span> exec <span class="token operator">-</span>a below is a bashism<span class="token punctuation">.</span> </span><span class="code-line"><span class="token property-access">exec</span> <span class="token operator">-</span>a <span class="token string">&quot;$0&quot;</span> <span class="token string">&quot;$HERE/chrome&quot;</span> <span class="token string">&quot;$@&quot;</span> </span></code></pre></div><p>搜索了系统其它地方(如 <code>/etc/environment</code>, <code>/etc/profile.d</code> 等), 也没有发现设置 <code>LD_LIBRARY_PATH</code> 的, 唯一的只有这个脚本有 <code>export LD_LIBRARY_PATH</code>, 而这个脚本只有在Chrome 启动的时候才会执行, 并且, 这样执行 <code>export LD_LIBRARY_PATH</code> 不应该影响到 gnome terminal 或 smplayer 的环境变量啊?</p> Sun, 06 Mar 2022 05:39:05 GMT ttyS3 mpvundefined symbolarchlinuxchrome https://ttys3.dev/blog/kitty kitty -- 一个被严重忽视的生产力利器 https://ttys3.dev/blog/kitty <p><a href="https://github.com/kovidgoyal/kitty">kitty</a> 是一个 GPU based terminal, 这类terminal 并不少, 比如老灯目前在用的 Alacritty.</p><p>kitty 可以说是, 老灯无意中安装上的, 今天本来想卸载它的, 结果把玩了一下, 发现这玩意设计上和性能上都不错.并且<a href="https://sw.kovidgoyal.net/kitty/">文档齐全</a>, 开发活跃.</p><p><strong>Alacritty</strong> 出生就自带 Rust 光环, 当前 star 数量约 37.8K. <strong>kitty</strong> 当前 star 数量才接近 13.9K.</p><p>当然, 这个 star 数量并不能说明什么, 因为 Rust 拥有众多的 Rustaceans (老灯也是铁杆 Rustacean) , 以 Rust 光环, 加上 &quot;<em><strong>the fastest terminal emulator&quot;</strong></em> 的营销口号, 获取 star 数量确实不在话下.</p><p>当然, <strong>kitty</strong> 也不是什么 <strong>Hello Kitty</strong>, 而是实实在在的一个功能完备的终端. Alacritty 在我看来, 只是配合 tmux 使用的一个辅助工具. 离开了 tmux 的 Alacritty 对我来说, 毫无用处, 甚至不如 Gnome Terminal.</p><p>我想有必要写文章分享一下 kitty 这么优秀的软件. (鉴于 kitty 的作者是如此低调)</p><p>很多时候, 你喜欢一个语言, 自然而然的会希望你手里用的工具都是基于这个语言的. 老灯便是如此. 但是今日试用了 kitty, 老灯觉得, 语言是不是 Rust 已经不重要了. <strong>kitty</strong> 的魅力足够让我抛弃语言之类的偏见.</p><p>kitty 具备完整的功能, 而 Alacritty 别说支持分屏了, 连最基本的多 tab 都不支持. 所以, 应该没有人直接用 Alacritty, 基本上都是搭配 tmux 之类的终端复用器来使用.</p><h2 id="关于-terminal-multiplexers"><a href="#关于-terminal-multiplexers" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>关于 terminal multiplexers</h2><p>terminal multiplexers 的典型代码当然是 <a href="https://github.com/tmux/tmux">tmux</a> 了, 当然, 这里是泛指这一类程序.</p><p>作者认为, terminal multiplexers 是一个 bad idea.</p><blockquote><p>First, terminal multiplexers are <a href="https://github.com/kovidgoyal/kitty/issues/391#issuecomment-638320745">a bad idea</a>, do not use them, if at all possible. kitty contains features that do all of what tmux does, but better, with the exception of remote persistence (<a href="https://github.com/kovidgoyal/kitty/issues/391">#391</a>). </p><p>In summary: multiplexers add unnecessary overhead, suffer from a complexity cascade, because they actually have to <strong>translate</strong> escape codes, modifying them in hackish ways to get them to work with their concepts of windows/sessions.</p><p>Energy/performance wise they are poison, every byte has to be parsed twice, once by the middleman and once by the terminal. And they act as a drag on the ecosystem as a whole, making it very hard to get any new features. Designing features becomes harder because you have to design for compatibility with a horrible hack and the diffusion into the ecosystem tends to get gated by basically a handful of individuals with, let&#x27;s say, very limited vision.</p></blockquote><p>机器翻译下吧:</p><blockquote><p>首先,终端多路复用器是一个坏主意,如果可能的话,不要使用它们。kitty 包含的功能做了Tmux 所做的一切,但更好,除了远程持久化(#391)。</p><p>总结:多路复用器增加了不必要的开销,遭受了复杂的级联,因为它们实际上必须<strong>翻译</strong>转义代码,以黑客的方式修改它们,以使它们与它们的窗口/会话概念一起工作。</p><p>能源/性能方面,它们是毒药,每一个字节都要被解析两次,一次由中间人解析,一次由终端解析。而且它们是整个生态系统的拖累,使其很难获得任何新功能。设计功能变得更加困难,因为你必须为兼容一个可怕的黑客而设计,而且扩散到生态系统中往往会被一小撮具有非常有限的视野的人所阻止。</p></blockquote><p>所以, 当你用着 tmux 还觉得它很高级的时候, 事实上它是一种很古老的东西, 从设计上来说, 它并不优雅, 只是解决了需求问题. 作为 tmux + Alacritty 用户, 其实一直也没深入了解 tmux 的实现, 今天读到 kitty 作者的这段话, 奇怪的知识又增加了.</p><h2 id="性能"><a href="#性能" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>性能</h2><p>kitty 的核心部分采用 C 编写, UI 界面采用 python 以方便扩展.</p><p>这里老灯采用这个脚本进行一个简单的测试(from <a href="https://github.com/alacritty/alacritty/issues/289#issuecomment-340283908">https://github.com/alacritty/alacritty/issues/289#issuecomment-340283908</a>):</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token keyword">for</span> <span class="token variable for-or-select">i</span> <span class="token keyword">in</span> <span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">..</span><span class="token number">400000</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">do</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\r&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\033[0K\033[1mBold\033[0m \033[7mInvert\033[0m \033[4mUnderline\033[0m&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\033[0K\033[1m\033[7m\033[4mBold &amp; Invert &amp; Underline\033[0m&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\033[0K\033[31m Red \033[32m Green \033[33m Yellow \033[34m Blue \033[35m Magenta \033[36m Cyan \033[0m&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\033[0K\033[1m\033[4m\033[31m Red \033[32m Green \033[33m Yellow \033[34m Blue \033[35m Magenta \033[36m Cyan \033[0m&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\033[0K\033[41m Red \033[42m Green \033[43m Yellow \033[44m Blue \033[45m Magenta \033[46m Cyan \033[0m&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\033[0K\033[1m\033[4m\033[41m Red \033[42m Green \033[43m Yellow \033[44m Blue \033[45m Magenta \033[46m Cyan \033[0m&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\033[0K\033[30m\033[41m Red \033[42m Green \033[43m Yellow \033[44m Blue \033[45m Magenta \033[46m Cyan \033[0m&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;\033[0K\033[30m\033[1m\033[4m\033[41m Red \033[42m Green \033[43m Yellow \033[44m Blue \033[45m Magenta \033[46m Cyan \033[0m&#x27;</span> </span><span class="code-line"><span class="token keyword">done</span> </span></code></pre></div><p>机器环境为 X11 + Nvidia + ArchLinux</p><p>Intel i9-9900 (16) @ 4.000GHz</p><p>Resolution: 3840x2160</p><ul><li>Alacritty 0.10.1 (2844606d) + tmux 3.2a <code>17s</code></li><li>kitty 0.24.3<code>24s</code></li><li>GNOME Terminal 3.42.2 using VTE 0.66.2 <code>24s</code></li><li>Wez Terminal 20220101-133340-7edc5b5a <code>44s</code></li></ul><p><code>Wez Terminal</code> 是真的卡. 跟 Alacritty 一样同样是 Rust 写的东西, 怎么速度上差这么多呢? 所以, 语言并不能决定性能. 还得看你怎么写的.</p><p>关于 WezTerminal 的性能差的问题, reddit 上<a href="https://www.reddit.com/r/rust/comments/hach2x/wezterm_a_gpuaccelerated_crossplatform_terminal/fv33wzl/">两年前就有人提了</a>, 没想到两年后还是这样.</p><h2 id="配置"><a href="#配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>配置</h2><p>kitty 基本上是开箱即用的.</p><p>但是由于我是一个 Alacritty + tmux 用户, 因此自然希望, 习惯上的很多快捷键能得以保留.</p><p>折腾好的配置在这: <a href="https://github.com/ttys3/my-kitty-config">https://github.com/ttys3/my-kitty-config</a></p><p>默认的<code>kitty_mod</code> ctrl+shift 保留下来了.</p><p>注意不要试图将 <code>kitty_mod</code> 设置成 <code>ctrl+a</code> , 这是不会工作的. 因为 <code>kitty_mod</code> has to be <strong><code>modifiers</code></strong> not keys. see <a href="https://github.com/kovidgoyal/kitty/discussions/3457#discussioncomment-587511">https://github.com/kovidgoyal/kitty/discussions/3457#discussioncomment-587511</a></p><p>You can download a sample <code>kitty.conf</code> file with all default settings and comments describing each setting by clicking: <a href="https://sw.kovidgoyal.net/kitty/_downloads/433dadebd0bf504f8b008985378086ce/kitty.conf"><code>sample kitty.conf</code></a>.</p><h2 id="kittens"><a href="#kittens" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Kittens</h2><p>kitten意为&quot;幼猫&quot;, 而 kitty 是&quot;猫咪&quot; 的意思. 这个取名也相当有意思.</p><p><code>kittens</code> 相当于 kitty 的插件. 内置的所有 kittens 可以在这里找到: <a href="https://sw.kovidgoyal.net/kitty/kittens_intro/">https://sw.kovidgoyal.net/kitty/kittens_intro/</a></p><h3 id="diff"><a href="#diff" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>diff</h3><p>老灯觉得这个 <a href="https://sw.kovidgoyal.net/kitty/kittens/diff/">kitty-diff</a> 显示的色彩效果是真的好, 咋一看以为打开了 gui 的 meld.</p><p><img alt="" src="https://sw.kovidgoyal.net/kitty/_images/diff.png"/></p><p>使用方法:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">kitty +kitten <span class="token function">diff</span> file1 file2 </span></code></pre></div><p>甚至还可以集成到 git, 将以下配置添加到 <code>~/.gitconfig</code> 中:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">diff</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">tool</span> <span class="token punctuation">=</span> <span class="token attr-value value">kitty</span> </span><span class="code-line"> <span class="token attr-name key">guitool</span> <span class="token punctuation">=</span> <span class="token attr-value value">kitty.gui</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">difftool</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">prompt</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"> <span class="token attr-name key">trustExitCode</span> <span class="token punctuation">=</span> <span class="token attr-value value">true</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">difftool &quot;kitty&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">cmd</span> <span class="token punctuation">=</span> <span class="token attr-value value">kitty +kitten diff $LOCAL $REMOTE</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">difftool &quot;kitty.gui&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">cmd</span> <span class="token punctuation">=</span> <span class="token attr-value value">kitty kitty +kitten diff $LOCAL $REMOTE</span> </span></code></pre></div><p>diff 功能老灯对比了一下同是 python 实现的 meld, 发现 meld 的 diff 能够区分同一行的不同字符的变动, 而 kitty 的并不能, 以下是对比图:</p><div><img alt="" src="https://ttys3.dev/static/assets/kitty-diff-2022-03-04_21-48-DVMB6PDK.png" width="1896" height="758"/></div><div><img alt="" src="https://ttys3.dev/static/assets/2022-03-04_21-52-YNSJRV26.png" width="1812" height="899"/></div><p>另一个问题是, 在 dark terminal colorscheme 下面, kitty 默认的白色背景的 diff 结果显得怪怪的, <a href="https://github.com/kovidgoyal/kitty/issues/2550">这里有一个黑色版</a>的, 不过老灯看着也不是很满意, 还不如直接用白色背景版的.</p><p>目前来说, <a href="https://github.com/dandavison/delta">delta</a> 的 diff 效果和配色默认用着也挺舒服的. 所以在kitty diff 功能改进之前, 老灯还是继续用 delta.</p><h3 id="icat"><a href="#icat" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>icat</h3><p><a href="https://sw.kovidgoyal.net/kitty/kittens/icat/">icat </a>可以直接在 kitty 里面显示图片, 老灯直接用 4k 图片测试过了, 显示效果相当好.</p><blockquote><p><a href="https://www.imagemagick.org/">ImageMagick</a> must be installed for <code>icat</code> to work.</p></blockquote><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token builtin class-name">alias</span> <span class="token variable assign-left">icat</span><span class="token operator">=</span><span class="token string">&quot;kitty +kitten icat&quot;</span> </span></code></pre></div><div><img alt="" src="https://ttys3.dev/static/assets/kitty-icat-2022-03-04_22-06-FH7GAL5N.png" width="2990" height="1981"/></div><h3 id="themes"><a href="#themes" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>themes</h3><p><a href="https://sw.kovidgoyal.net/kitty/kittens/themes/">themes</a> 可以让你即时预览主题效果, 并支持一键切换.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">kitty +kitten themes </span></code></pre></div><div><img alt="" src="https://ttys3.dev/static/assets/kitty-themes-2022-03-04_22-12-GC24Z7MS.png" width="1379" height="1142"/></div><h3 id="search"><a href="#search" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>search</h3><p><a href="https://github.com/trygveaa/kitty-kitten-search">https://github.com/trygveaa/kitty-kitten-search</a></p><p>这是一个第三方的 kitten</p><h2 id="troubleshooting"><a href="#troubleshooting" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Troubleshooting</h2><h3 id="1-zoom-panel-功能"><a href="#1-zoom-panel-功能" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. zoom panel 功能</h3><p>kitty 并没有像 tmux 一样自带这个功能, 但是其扩展能力极强, 实现这个非常轻松.</p><p>参考 <a href="https://sw.kovidgoyal.net/kitty/kittens/custom/#using-kittens-to-script-kitty-without-any-terminal-ui">https://sw.kovidgoyal.net/kitty/kittens/custom/#using-kittens-to-script-kitty-without-any-terminal-ui</a></p><p>在 kitty 配置目录下创建文件 <code>~/.config/kitty/zoom_toggle.py</code>, 内容如下:</p><div class="relative"><pre><code class="code-highlight language-python"><span class="code-line"><span class="token keyword">def</span> <span class="token function">main</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token keyword">pass</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">from</span> kittens<span class="token punctuation">.</span>tui<span class="token punctuation">.</span>handler <span class="token keyword">import</span> result_handler </span><span class="code-line"><span class="token punctuation annotation decorator">@result_handler</span><span class="token punctuation">(</span>no_ui<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token keyword">def</span> <span class="token function">handle_result</span><span class="token punctuation">(</span>args<span class="token punctuation">,</span> answer<span class="token punctuation">,</span> target_window_id<span class="token punctuation">,</span> boss<span class="token punctuation">)</span><span class="token punctuation">:</span> </span><span class="code-line"> tab <span class="token operator">=</span> boss<span class="token punctuation">.</span>active_tab </span><span class="code-line"> <span class="token keyword">if</span> tab <span class="token keyword">is</span> <span class="token keyword">not</span> <span class="token boolean">None</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token keyword">if</span> tab<span class="token punctuation">.</span>current_layout<span class="token punctuation">.</span>name <span class="token operator">==</span> <span class="token string">&#x27;stack&#x27;</span><span class="token punctuation">:</span> </span><span class="code-line"> tab<span class="token punctuation">.</span>last_used_layout<span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">else</span><span class="token punctuation">:</span> </span><span class="code-line"> tab<span class="token punctuation">.</span>goto_layout<span class="token punctuation">(</span><span class="token string">&#x27;stack&#x27;</span><span class="token punctuation">)</span> </span></code></pre></div><p>注意, <code>stack</code> layout 必须要<a href="https://sw.kovidgoyal.net/kitty/conf.html#opt-kitty.enabled_layouts">被允许</a>.</p><blockquote><p>The <strong>first</strong> layout listed in <code>enabled_layouts</code> in kitty.conf will be <strong>the default</strong>. </p></blockquote><p>ref <a href="https://github.com/kovidgoyal/kitty/issues/2258#issuecomment-571201141">https://github.com/kovidgoyal/kitty/issues/2258#issuecomment-571201141</a></p><p>老灯现在的配置是 <code>enabled_layouts splits,stack</code></p><p>实现这一功能的 issue 在这 <a href="https://github.com/kovidgoyal/kitty/issues/870#issuecomment-429313856">https://github.com/kovidgoyal/kitty/issues/870#issuecomment-429313856</a></p><p>通过<a href="https://github.com/kovidgoyal/kitty/commit/787100a4dcd3d9c338bfc15511e4a4824a865e6a">提交记录</a>发现, 作者实现这一功能的支持, 只改动了几行代码. 不得不佩服.</p><h3 id="2-session-保存和加载"><a href="#2-session-保存和加载" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. session 保存和加载</h3><p>已经有讨论, 但是并无进展:</p><p><a href="https://github.com/kovidgoyal/kitty/issues/1197#issuecomment-785435558">https://github.com/kovidgoyal/kitty/issues/1197#issuecomment-785435558</a></p><p>在 tmux 里面, 我们可以使用 <code>tmux-plugins/tmux-resurrect</code> 和 <code>tmux-plugins/tmux-continuum</code> 两个插件实现<strong>自动</strong> dump 和 加载 session</p><p>kitty 这边目前好像还没有这样直接就拿来能用的插件方案.</p><p>kitty 内置了 session 支持, 也就是说它支持 session restore, 但是 dump 这一方便好像没有比较官方的支持.</p><p>如果能在退出时自动 dump 出可以直接用于 restore 的 session 配置, 那么其实这个功能就会比较好实现了.</p><p>静态 session 配置比较简单: <a href="https://github.com/ttys3/my-kitty-config#session-restore">https://github.com/ttys3/my-kitty-config#session-restore</a></p><p>dump 功能目前有<a href="https://github.com/dflock/kitty-save-session">第三方实现</a>可用: <a href="https://github.com/kovidgoyal/kitty/issues/1197#issuecomment-785435558">https://github.com/kovidgoyal/kitty/issues/1197#issuecomment-785435558</a></p><p>注意 <code>kitty @ ls</code> 需要开启 <code>allow_remote_control yes</code> (改这个需要重启kitty, reload 配置不会生效)</p><h3 id="3-status-line"><a href="#3-status-line" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. status line</h3><p>老灯 tmux 下的 status line 大概长这样:</p><div><img alt="" src="https://ttys3.dev/static/assets/my-tmux-status-line-2022-03-04_11-26-4VA2BEUD.png" width="1207" height="122"/></div><p>这个不是刚需, 而且, 可以采用 DE 顶部的 status line 解决</p><p>kitty 有 panel 貌似可以实现类似的功能: <a href="https://sw.kovidgoyal.net/kitty/kittens/panel/">https://sw.kovidgoyal.net/kitty/kittens/panel/</a></p><p>不过我一直没能让它显示出来...</p><p>搞笑的是, 有人问这个作者, 文档里面的 demo 脚本, 作者回答这个涉及隐私信息不能给你 Orz</p><p><a href="https://github.com/kovidgoyal/kitty/issues/2523">https://github.com/kovidgoyal/kitty/issues/2523</a></p><p>lol. wtf? A sensitive status command? this is a first.</p><h3 id="4-terminfo-问题"><a href="#4-terminfo-问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4. terminfo 问题</h3><p>如果你尝试ssh到远程机器, 可能会发现你本机的zsh报错:</p><blockquote><p>/home/user007/.zsh_compatible:bindkey:2: cannot bind to an empty key sequence</p></blockquote><p>这个问题其实不只存在于 kitty, 任何有自己独立的 <code>terminfo</code> 的 terminal (且其信息没有在<code>ncurses</code>中内置), 基本上都会有这个问题. 比如 Alacritty 也有这个问题.</p><p>这个问题官方faq文档里面也有说明: <a href="https://sw.kovidgoyal.net/kitty/faq/#i-get-errors-about-the-terminal-being-unknown-or-opening-the-terminal-failing-when-sshing-into-a-different-computer">I get errors about the terminal being unknown or opening the terminal failing when SSHing into a different computer?</a></p><blockquote><p>This happens because the kitty terminfo files are not available on the server. You can ssh in using the following command which will automatically copy the terminfo files to the server:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">kitty +kitten <span class="token function">ssh</span> myserver </span></code></pre></div><p>This ssh kitten takes all the same command line arguments as ssh, you can alias it to ssh in your shell’s rc files to avoid having to type it each time:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token builtin class-name">alias</span> <span class="token variable assign-left">ssh</span><span class="token operator">=</span><span class="token string">&quot;kitty +kitten ssh&quot;</span> </span></code></pre></div></blockquote><p><a href="https://github.com/kovidgoyal/kitty/issues/879">https://github.com/kovidgoyal/kitty/issues/879</a></p><p>有人建议提交 <code>xterm-kitty</code> terminfo 到 <code>ncurses</code> 数据库, 这样ssh到安装了较新的 <code>ncurses</code> 的系统上便不会有识别不了<code>xterm-kitty</code> 的问题.</p><p>不过这个作者说, <code>ncurses</code> 那边的人不喜欢他, 不给它集成进去. 2018年的issue, 现在2022年了, 确实是件难事哈.</p><p><a href="https://github.com/kovidgoyal/kitty/issues/879#issuecomment-419686348">https://github.com/kovidgoyal/kitty/issues/879#issuecomment-419686348</a></p><blockquote><p>So to summarize the ncurses maintainer&#x27;s response:</p><ol><li>He does not like kitty&#x27;s license (I&#x27;m happy to change the license of just the terminfo file to CC license, if needed)</li><li>He does not like kitty TERM variable. This is not going to change as it would break lots of programs that turn on various features when they see a TERM variable of the type xterm-whatever. A situation that was created by the ncurses maintainer refusing to add new capabilities for various things.</li><li>He does not like the fact that kitty has introduced new capabilities into the terminal ecosystem</li></ol><p>About what I expected from my previous interactions with him. He excels at presenting excuses to maintain the status quo. I&#x27;m afraid I am not interested in tying kitty to this particular boat anchor. There&#x27;s a reason the terminal ecosystem has stagnated for so long, and ncurses is a big part of that stagnation.</p></blockquote><p>使用 <code>kitty +kitten ssh</code> 之类的方式连接也是挺蛋疼的. 老灯干脆让它标榜自己为 <code>xterm-256color</code> 算了, 就像我给 Alacritty 设置的一样. 另外, Gnome Terminal 也是用的 <code>xterm-256color</code> , 所以, 这个应该问题不大.</p><p>编辑 <code>kitty.conf</code>设置 <code>term xterm-256color</code> 即可.</p><p>ref: <a href="https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.term">https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.term</a></p><h3 id="5-kitty-误变成-inodedirectory-的默认打开程序"><a href="#5-kitty-误变成-inodedirectory-的默认打开程序" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>5. kitty 误变成 inode/directory 的默认打开程序</h3><p>不知是我手抖误设置了还是 kitty 安装的时候设置的.</p><p>经过检查, 发现 <code>/usr/share/applications/mimeinfo.cache</code> 文件中 <code>inode/directory</code> 的值变成了 <code>kitty-open.desktop</code> 跑在了 <code>org.gnome.Nautilus.desktop</code> 的前面.</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token attr-name key">inode/directory</span><span class="token punctuation">=</span><span class="token attr-value value">kitty-open.desktop;org.gnome.Nautilus.desktop;vifm.desktop;visual-studio-code.desktop;</span> </span></code></pre></div><p>当然, 我们不用动<code>/usr/share/applications/mimeinfo.cache</code>这个文件, 编辑 <code>~/.config/mimeapps.list</code> 加上下面这一行即可修正:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token attr-name key">inode/directory</span><span class="token punctuation">=</span><span class="token attr-value value">org.gnome.Nautilus.desktop</span> </span></code></pre></div><h2 id="目前缺少的功能"><a href="#目前缺少的功能" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>目前缺少的功能</h2><ol><li><h3 id="copy-mode--vim-mode"><a href="#copy-mode--vim-mode" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>copy mode / vim mode</h3></li></ol><p>see <a href="https://github.com/kovidgoyal/kitty/issues/1698">https://github.com/kovidgoyal/kitty/issues/1698</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p>kitty icon 来自 <a href="https://github.com/DinkDonk/kitty-icon">https://github.com/DinkDonk/kitty-icon</a></p><p><a href="https://github.com/kovidgoyal/kitty/issues/3312#issuecomment-778619468">Unicode 7.0 text characters aren&#x27;t displayed / too wide #3312</a></p><p><a href="https://sw.kovidgoyal.net/kitty/overview/#design-philosophy">https://sw.kovidgoyal.net/kitty/overview/#design-philosophy</a></p><p><a href="https://sw.kovidgoyal.net/kitty/kittens_intro/#kittens">https://sw.kovidgoyal.net/kitty/kittens_intro/#kittens</a></p><p><a href="https://sw.kovidgoyal.net/kitty/kittens/themes/#how-it-works">https://sw.kovidgoyal.net/kitty/kittens/themes/#how-it-works</a></p><p><a href="https://sw.kovidgoyal.net/kitty/overview/#other-keyboard-shortcuts">https://sw.kovidgoyal.net/kitty/overview/#other-keyboard-shortcuts</a></p><p><a href="https://sw.kovidgoyal.net/kitty/conf.html#opt-kitty.enabled_layouts">https://sw.kovidgoyal.net/kitty/conf.html#opt-kitty.enabled_layouts</a></p><p><a href="https://github.com/dflock/kitty-save-session">https://github.com/dflock/kitty-save-session</a></p><p><a href="https://github.com/trygveaa/kitty-kitten-search">https://github.com/trygveaa/kitty-kitten-search</a></p> Thu, 03 Mar 2022 18:40:36 GMT ttyS3 kittyterminalalacrittytmux https://ttys3.dev/blog/rust-motd-setup rust-motd Setup https://ttys3.dev/blog/rust-motd-setup <p>2022-03-04 update:</p><p>gdm 用户最好不要启用 motd. 否则在登录界面会卡很久才进去.</p><p>有办法可以禁用这一行为, see <a href="https://bbs.archlinux.org/viewtopic.php?pid=1684018#p1684018">https://bbs.archlinux.org/viewtopic.php?pid=1684018#p1684018</a></p><p>moving the following line:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">session optional pam_motd.so <span class="token variable assign-left">motd</span><span class="token operator">=</span>/etc/motd </span></code></pre></div><p>from <code>/etc/pam.d/system-login</code> to <code>/etc/pam.d/sshd</code>.</p><p>The result is that the motd is no longer displayed in gdm, but it&#x27;s still displayed when logging in through ssh.</p><p>--------------------------------------------------------------------------------</p><p><a href="https://github.com/rust-motd/rust-motd">https://github.com/rust-motd/rust-motd</a></p><blockquote><p>Beautiful, useful, configurable MOTD generation with zero runtime dependencies</p></blockquote><p>如果显示 hostname 时想使用 figlet 的话需要安装一下:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">paru <span class="token variable parameter">-S</span> figlet </span></code></pre></div><p>the oneshot service</p><div class="relative"><pre><code class="code-highlight language-shel"><span class="code-line">cat &lt;&lt;EOF &gt; /etc/systemd/system/rust-motd.service </span><span class="code-line"> </span><span class="code-line">[Unit] </span><span class="code-line">Description=run rust-motd </span><span class="code-line">Wants=network-online.target </span><span class="code-line">After=network-online.target </span><span class="code-line"> </span><span class="code-line">[Service] </span><span class="code-line">Restart=on-failure </span><span class="code-line">TimeoutStopSec=5 </span><span class="code-line">StandardOutput=file:/etc/motd </span><span class="code-line">ExecStart=rust-motd /root/.config/rust-motd/config.toml </span><span class="code-line">Type=oneshot </span><span class="code-line"> </span><span class="code-line">[Install] </span><span class="code-line">WantedBy=default.target </span><span class="code-line"> </span><span class="code-line">EOF </span></code></pre></div><p>the timer:</p><div class="relative"><pre><code class="code-highlight language-shel"><span class="code-line">cat &lt;&lt;EOF &gt; /etc/systemd/system/rust-motd.timer </span><span class="code-line"> </span><span class="code-line">[Unit] </span><span class="code-line">Description=Run rust-motd every 5 minutes and on boot </span><span class="code-line"> </span><span class="code-line">[Timer] </span><span class="code-line">OnBootSec=30s </span><span class="code-line">OnUnitActiveSec=5min </span><span class="code-line"> </span><span class="code-line">[Install] </span><span class="code-line">WantedBy=timers.target </span><span class="code-line"> </span><span class="code-line">EOF </span></code></pre></div><p>the config:</p><p>注意替换配置中的 <code>Your-Location-Here</code> 为你的实际城市名(英文).</p><p>替换 <code>user001</code> 为你自己的用户名.</p><div class="relative"><pre><code class="code-highlight language-shel"><span class="code-line">cat &lt;&lt;EOF &gt; /root/.config/rust-motd/config.toml </span><span class="code-line">[global] </span><span class="code-line"> progress_full_character = &quot;=&quot; </span><span class="code-line"> progress_empty_character = &quot;=&quot; </span><span class="code-line"> progress_prefix = &quot;[&quot; </span><span class="code-line"> progress_suffix = &quot;]&quot; </span><span class="code-line"> time_format = &quot;%Y-%m-%d %H:%M:%S&quot; </span><span class="code-line"> </span><span class="code-line"> [banner] </span><span class="code-line">color = &quot;red&quot; </span><span class="code-line"> command = &quot;hostname | figlet -f slant&quot; </span><span class="code-line"># if you don&#x27;t want a dependency on figlet, you can generate your </span><span class="code-line"># banner however you want, put it in a file, and then use something like: </span><span class="code-line"># command = &quot;cat banner.txt&quot; </span><span class="code-line"> </span><span class="code-line"> [weather] </span><span class="code-line"> url = &quot;https://wttr.in/Your-Location-Here?0&quot; </span><span class="code-line"> proxy = &quot;http://127.0.0.1:7890&quot; </span><span class="code-line"> </span><span class="code-line"># [service_status] </span><span class="code-line"># Accounts = &quot;accounts-daemon&quot; </span><span class="code-line"># Cron = &quot;cron&quot; </span><span class="code-line"> </span><span class="code-line">[docker_status] </span><span class="code-line"># Local containers MUST start with a slash </span><span class="code-line"># https://github.com/moby/moby/issues/6705 </span><span class="code-line">#&quot;/nextcloud-nextcloud-mariadb-1&quot; = &quot;Nextcloud Database&quot; </span><span class="code-line"> </span><span class="code-line"> [uptime] </span><span class="code-line"> prefix = &quot;Up&quot; </span><span class="code-line"> </span><span class="code-line"> [user_service_status] </span><span class="code-line"> clash = &quot;clash&quot; </span><span class="code-line"> systemd-resolved = &quot;systemd-resolved&quot; </span><span class="code-line"> gpg-agent = &quot;gpg-agent&quot; </span><span class="code-line"> </span><span class="code-line"># [ssl_certificates] </span><span class="code-line"># sort_method = &quot;manual&quot; </span><span class="code-line"># </span><span class="code-line"># [ssl_certificates.certs] </span><span class="code-line"># CertName1 = &quot;/path/to/cert1.pem&quot; </span><span class="code-line"># CertName2 = &quot;/path/to/cert2.pem&quot; </span><span class="code-line"> </span><span class="code-line"> [filesystems] </span><span class="code-line"> root = &quot;/&quot; </span><span class="code-line"> home = &quot;/home&quot; </span><span class="code-line"> </span><span class="code-line"> [memory] </span><span class="code-line"> swap_pos = &quot;beside&quot; # or &quot;below&quot; or &quot;none&quot; </span><span class="code-line"> </span><span class="code-line"># [fail_2_ban] </span><span class="code-line"># jails = [&quot;sshd&quot;, &quot;anotherjail&quot;] </span><span class="code-line"> </span><span class="code-line"> [last_login] </span><span class="code-line"> root = 2 </span><span class="code-line"> user001 = 1 </span><span class="code-line"> </span><span class="code-line">[last_run] </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">EOF </span></code></pre></div><p>enable:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">sudo</span> systemctl <span class="token builtin class-name">enable</span> <span class="token variable parameter">--now</span> rust-motd.timer </span></code></pre></div> Tue, 04 Jan 2022 18:36:01 GMT ttyS3 rustmotdsystemd-timer https://ttys3.dev/blog/debugging-delta-0.10.x-slowdown-problem-on-linux Debugging Delta 0.10.x slowdown problem on Linux https://ttys3.dev/blog/debugging-delta-0.10.x-slowdown-problem-on-linux <p>其实从 0.10.x 开始就觉得 delta 老慢了, 但是一直没怀疑到是 delta 自身的bug.</p><p>有一天, 正好在 github 上面看到有人提 <a href="https://github.com/dandavison/delta/issues/824">issue</a>, 说当系统进程较多时, delta 扫描所有进程, 这里花了大量时间导致变慢.</p><p>然后作者很快发布了一个新版本 <a href="https://github.com/dandavison/delta/releases/tag/0.11.2">0.11.2</a> , 说这个问题解决了扫进程时慢的问题.</p><p>但是我到手一测试, 发现依然可以肉眼感受到这个&quot;慢&quot;.</p><h2 id="flamegraph-分析-定位问题"><a href="#flamegraph-分析-定位问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>flamegraph 分析: 定位问题</h2><p>先上 flamegraph 分析一波.</p><p>完整的交互式svg flamegraph (需要用web浏览器打开):</p><div><img alt="delta-flamegraph.svg" src="https://ttys3.dev/static/assets/delta-flamegraph-V5UW5SIB.svg" width="1200" height="630"/></div><p>找到tower top:</p><div><img alt="delta-flamegraph-overview-2021-12-21_01-35.png" src="https://ttys3.dev/static/assets/delta-flamegraph-overview-2021-12-21_01-35-W2C2ZCMN.png" width="1977" height="1246"/></div><p>展开:</p><div><img alt="delta-tower-top-flamegraph-2021-12-21_01-36.png" src="https://ttys3.dev/static/assets/delta-tower-top-flamegraph-2021-12-21_01-36-MGF3MQE6.png" width="1269" height="1271"/></div><p>很快发现, 锅是 <code>sysinfo::linux::processor::get_cpu_frequency</code> 的, 它发起的系统调用(用来检测每个 cpu logic core 的频率)很慢.</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token property literal-property">delta</span><span class="token operator">:</span><span class="token operator">:</span>utils<span class="token operator">:</span><span class="token operator">:</span>process<span class="token operator">:</span><span class="token operator">:</span>determine_calling_process </span><span class="code-line"><span class="token operator">|</span> </span><span class="code-line"><span class="token constant">V</span> </span><span class="code-line"><span class="token property literal-property">sysinfo</span><span class="token operator">:</span><span class="token operator">:</span>linux<span class="token operator">:</span><span class="token operator">:</span>system<span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">System</span><span class="token operator">:</span><span class="token operator">:</span>refresh_processors </span><span class="code-line"><span class="token operator">|</span> </span><span class="code-line">v </span><span class="code-line"><span class="token property literal-property">sysinfo</span><span class="token operator">:</span><span class="token operator">:</span>linux<span class="token operator">:</span><span class="token operator">:</span>processor<span class="token operator">:</span><span class="token operator">:</span>get_cpu_frequency </span></code></pre></div><p>最简单验证, 直接注释掉 <code>determine_calling_process</code> 对 <code>sysinfo::linux::system::System::refresh_processors</code> 的调用,</p><p>速度马上恢复了. 从原来的 300ms 降到了 50ms 左右了.</p><p>不过禁用这个调用, 并没有真正解决问题, 而只是屏蔽了这个问题.</p><p>为什么需要获取进程信息, delta 的作者特意<a href="https://github.com/dandavison/delta/issues/824#issuecomment-988952003">详细解释</a>了:</p><blockquote><p>The downside of disabling that call is that delta will not be able to handle any of the following:</p></blockquote><blockquote><p><code>git diff --word-diff</code> / <code>git diff --color-words</code> <code>git grep</code> and other grep&#x27;s (but it will handle <code>rg --json</code>) <code>git show $commit:$file</code> <code>git blame</code> language detection So that would be a shame, and I&#x27;d like to find a solution whereby we can do the process inspection in a way that is fast for all users.</p></blockquote><p>如果不能获取进程信息, 那么这些高级功能(0.10版本引入的, 0.9没有)全没了. 这显然是不可接受的.</p><hr/><p>delta src/utils/process.rs <code>sysinfo::System::new()</code>:</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">impl</span> <span class="token class-name">ProcInfo</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name">ProcInfo</span> <span class="token punctuation">{</span> </span><span class="code-line"> info<span class="token punctuation">:</span> <span class="token namespace">sysinfo<span class="token punctuation">::</span></span><span class="token class-name">System</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p><code>sysinfo::System::new()</code> :</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token function">new_with_specifics</span><span class="token punctuation">(</span><span class="token class-name">RefreshKind</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>new_with_specifics will always try to refresh_processors:</p><p>by default, !refreshes.cpu() result in !false , so it is true:</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">fn</span> <span class="token function function-definition">new_with_specifics</span><span class="token punctuation">(</span>refreshes<span class="token punctuation">:</span> <span class="token class-name">RefreshKind</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">System</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// ...</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token operator">!</span>refreshes<span class="token punctuation">.</span><span class="token function">cpu</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> s<span class="token punctuation">.</span><span class="token function">refresh_processors</span><span class="token punctuation">(</span><span class="token class-name">None</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// We need the processors to be filled.</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> s<span class="token punctuation">.</span><span class="token function">refresh_specifics</span><span class="token punctuation">(</span>refreshes<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// ...</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>there seems no way to forbbide refresh_processors call.</p><p>if we change the new to sysinfo::System::new_with_specifics(sysinfo::RefreshKind::new().with_cpu())</p><p>the first s.refresh_processors(None); will not get called.</p><p>but in s.refresh_specifics(refreshes);, it get called again.</p><p>所以, 这种情况, 不修改上游代码无法解决问题.</p><h2 id="模拟复现"><a href="#模拟复现" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>模拟复现</h2><p>简单写了个 demo (完整的demo代码见repo: <a href="https://github.com/ttys3/get-cpu-frequency-slow">https://github.com/ttys3/get-cpu-frequency-slow</a>):</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>fs<span class="token punctuation">::</span></span><span class="token class-name">File</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>io<span class="token punctuation">::</span></span><span class="token class-name">Read</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Instant</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>env<span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">const</span> <span class="token constant">DEFAULT_CPU_NUM</span><span class="token punctuation">:</span> <span class="token keyword">i32</span> <span class="token operator">=</span> <span class="token number">16</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">fn</span> <span class="token function function-definition">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> args <span class="token operator">=</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">args</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// skip self</span> </span><span class="code-line"> args<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// your logic CPU core number</span> </span><span class="code-line"> <span class="token keyword">let</span> num_cpu <span class="token operator">=</span> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>num_cpu<span class="token punctuation">)</span> <span class="token operator">=</span> args<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> num_cpu<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap_or</span><span class="token punctuation">(</span><span class="token constant">DEFAULT_CPU_NUM</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token constant">DEFAULT_CPU_NUM</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// weather force read from /proc/cpuinfo, it is important because when</span> </span><span class="code-line"> <span class="token comment">// the system has NO /sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq</span> </span><span class="code-line"> <span class="token comment">// this program run rather fast</span> </span><span class="code-line"> <span class="token keyword">let</span> force_cpuinfo <span class="token operator">=</span> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>force_cpuinfo<span class="token punctuation">)</span> <span class="token operator">=</span> args<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> force_cpuinfo<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token keyword">bool</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap_or</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token boolean">false</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token property macro">println!</span><span class="token punctuation">(</span><span class="token string">&quot;num_cpu={} force_cpuinfo={}&quot;</span><span class="token punctuation">,</span> num_cpu<span class="token punctuation">,</span> force_cpuinfo<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> force_cpuinfo <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">println!</span><span class="token punctuation">(</span><span class="token string">&quot;skip readding cpu freq from sysfs, directly to /proc/cpuinfo&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">let</span> start <span class="token operator">=</span> <span class="token class-name">Instant</span><span class="token punctuation">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// this for loop simulate the logic in `refresh_processors()`</span> </span><span class="code-line"> <span class="token comment">// see https://github.com/GuillaumeGomez/sysinfo/blob/01218743c7e656b7f12f530713ba417d2c5940ad/src/linux/system.rs#L146</span> </span><span class="code-line"> <span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token number">0</span><span class="token punctuation">..</span>num_cpu <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">get_cpu_frequency</span><span class="token punctuation">(</span>force_cpuinfo<span class="token punctuation">,</span> i <span class="token keyword">as</span> <span class="token keyword">usize</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">let</span> duration <span class="token operator">=</span> start<span class="token punctuation">.</span><span class="token function">elapsed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property macro">println!</span><span class="token punctuation">(</span><span class="token string">&quot;total time elapsed in get_cpu_frequency()x{} is: {:?}&quot;</span><span class="token punctuation">,</span> num_cpu<span class="token punctuation">,</span> duration<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// the func `get_cpu_frequency` took from https://docs.rs/crate/sysinfo/0.19.2/source/src/linux/processor.rs</span> </span><span class="code-line"><span class="token comment">// mainly for debugging and verify that delta 0.10.x slowdown problem is caused by `sysinfo` crate</span> </span><span class="code-line"><span class="token comment">// see https://github.com/dandavison/delta/issues/839</span> </span><span class="code-line"><span class="token comment">// added force_cpuinfo parameter</span> </span><span class="code-line"><span class="token keyword">fn</span> <span class="token function function-definition">get_cpu_frequency</span><span class="token punctuation">(</span>force_cpuinfo<span class="token punctuation">:</span> <span class="token keyword">bool</span><span class="token punctuation">,</span> cpu_core_index<span class="token punctuation">:</span> <span class="token keyword">usize</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">u64</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> s <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token operator">!</span>force_cpuinfo <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token class-name">File</span><span class="token punctuation">::</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token property macro">format!</span><span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;/sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> cpu_core_index </span><span class="code-line"> <span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">and_then</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token keyword">mut</span> f<span class="token punctuation closure-punctuation">|</span></span> f<span class="token punctuation">.</span><span class="token function">read_to_string</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> s<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">is_ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> freq_option <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token char">&#x27;\n&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>freq_string<span class="token punctuation">)</span> <span class="token operator">=</span> freq_option <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Ok</span><span class="token punctuation">(</span>freq<span class="token punctuation">)</span> <span class="token operator">=</span> freq_string<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token keyword">u64</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> freq <span class="token operator">/</span> <span class="token number">1000</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">println!</span><span class="token punctuation">(</span><span class="token string">&quot;try get cpu freq from sysfs failed, fallback to /proc/cpuinfo&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> s<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token class-name">File</span><span class="token punctuation">::</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token string">&quot;/proc/cpuinfo&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">and_then</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token keyword">mut</span> f<span class="token punctuation closure-punctuation">|</span></span> f<span class="token punctuation">.</span><span class="token function">read_to_string</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> s<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">is_err</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword">let</span> find_cpu_mhz <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token char">&#x27;\n&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>line<span class="token punctuation closure-punctuation">|</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> line<span class="token punctuation">.</span><span class="token function">starts_with</span><span class="token punctuation">(</span><span class="token string">&quot;cpu MHz\t&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token operator">||</span> line<span class="token punctuation">.</span><span class="token function">starts_with</span><span class="token punctuation">(</span><span class="token string">&quot;BogoMIPS&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token operator">||</span> line<span class="token punctuation">.</span><span class="token function">starts_with</span><span class="token punctuation">(</span><span class="token string">&quot;clock\t&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token operator">||</span> line<span class="token punctuation">.</span><span class="token function">starts_with</span><span class="token punctuation">(</span><span class="token string">&quot;bogomips per cpu&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> find_cpu_mhz </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">and_then</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>line<span class="token punctuation closure-punctuation">|</span></span> line<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token char">&#x27;:&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">last</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">and_then</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>val<span class="token punctuation closure-punctuation">|</span></span> val<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">&quot;MHz&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">::</span><span class="token operator">&lt;</span><span class="token keyword">f64</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>speed<span class="token punctuation closure-punctuation">|</span></span> speed <span class="token keyword">as</span> <span class="token keyword">u64</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">unwrap_or_default</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>验证结果:</p><p>当从 <code>/sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq</code> 读取时, 存在系统调用获取单个 cpu 频率, 非常慢, 如果是解析 <code>/proc/cpuinfo</code> 则非常快.</p><p>很明显, 我的情况是从<code>/sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq</code> 读取.</p><p>由于我的 CPU 是 8c16t的:</p><blockquote><p>a single run will cost about 16ms, thus 16 core CPU result in about 256ms</p></blockquote><p>所以, CPU 逻辑核越多, delta 越慢.</p><p>另一哥们就更惨了, 他是 32 thread 的 CPU, delta 每次执行差不多要花1秒多! (see <a href="https://github.com/dandavison/delta/issues/844">https://github.com/dandavison/delta/issues/844</a>)</p><h2 id="国外开源氛围"><a href="#国外开源氛围" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>国外开源氛围</h2><p>我给 delta 提了个 issue, 然后发现上游有问题.</p><p>delta 作者 dandavison 当时提出了两个方案: 一是给上游提个issue尝试解决, 二是换别的库. 比如 <a href="https://docs.rs/heim/0.0.11/heim/process/struct.Process.html">https://docs.rs/heim/0.0.11/heim/process/struct.Process.html</a></p><p>最终 delta 作者去 upstream 提 issue了: <a href="https://github.com/GuillaumeGomez/sysinfo/issues/632">https://github.com/GuillaumeGomez/sysinfo/issues/632</a></p><p>几经折腾, <code>sysinfo</code> 的作者终于将代码改成满足 delta 的需求场景了.</p><p>delta 的需求是: 只需要获取进程的父进程id, 而不需要执行进程的 cpu 执行时间.</p><p>目前 delta 0.11.3 已经发布, 解决了上述 Linux 下面慢的问题. <a href="https://github.com/dandavison/delta/releases/tag/0.11.3">https://github.com/dandavison/delta/releases/tag/0.11.3</a></p><p>所以, 国外的开源作者, 一般还都是挺友好的, 大家互相合作.</p><p>delta 作者并没有因为是我提的 issue 而要求我去 sysinfo 作者那里继续提 issue, 而是 默默地自己去主动提 issue 解决了.</p><p>sysinfo 作者也并没有用任何借口拒绝重构代码,添加选项. 更没有以&quot;这是你的小众需求, 我这个代码在90% 的情况下都不会有你说的性能问题的.&quot; 而关闭 issue, 而是三番五次的改进, 最终, 他还主动跑到 delta 的 PR 下面来确认工作 OK (see <a href="https://github.com/dandavison/delta/pull/845#issuecomment-991650195">https://github.com/dandavison/delta/pull/845#issuecomment-991650195</a>).</p><h2 id="其它思考"><a href="#其它思考" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它思考</h2><blockquote><ol><li>这个问题跟Linux系统调用有关, 而且是跟硬件有关, CPU 逻辑核越多的电脑上越慢. 至少 CPU 逻辑核心数量 &gt; 10 个以上, 人才可能容易感知到这种执行速度下降.</li></ol></blockquote><blockquote><ol start="2"><li>不能盲目相信 benchmark 工作的结果, 因为 benchmark 的时候调用存在缓存, 导致结果错误. 一个简单的 <code>sleep 1</code> 可以模拟真实场景.</li></ol></blockquote><p>using benchmark tool like <a href="https://github.com/sharkdp/hyperfine">hyperfine</a> will <strong>NOT</strong> present the problem,</p><p>something like <code>hyperfine -r 1000 &#x27;delta Cargo.toml Cargo.toml.bak&#x27;</code> will give you <strong>wrong conclusion</strong></p><p>the reason is <code>caching</code> affects the real world problem. although the benchmark tool is OK, and it also works as expected.</p><p>it shows the result like this (6 core machine):</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">❯ hyperfine <span class="token variable parameter">-r</span> <span class="token number">1000</span> <span class="token string">&#x27;delta Cargo.toml Cargo.toml.bak&#x27;</span> </span><span class="code-line">Benchmark <span class="token number">1</span>: delta Cargo.toml Cargo.toml.bak </span><span class="code-line"> Time <span class="token punctuation">(</span>mean ± σ<span class="token punctuation">)</span>: <span class="token number">55.3</span> ms ± <span class="token number">8.7</span> ms <span class="token punctuation">[</span>User: <span class="token number">47.1</span> ms, System: <span class="token number">5.8</span> ms<span class="token punctuation">]</span> </span><span class="code-line"> Range <span class="token punctuation">(</span>min … max<span class="token punctuation">)</span>: <span class="token number">50.7</span> ms … <span class="token number">149.7</span> ms <span class="token number">1000</span> runs </span></code></pre></div><p>but in real world, users will not always run <code>git diff</code> continuous. so the <code>cacehing</code> will not work. and every time the user may get the delay.</p><p>in real world, it is more like this:</p><p>I use a simple <code>sleep 1</code> to make the <code>caching</code> not work any more.</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token keyword">for</span> <span class="token variable"><span class="token punctuation">((</span> c<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">;</span> c<span class="token operator">&lt;=</span><span class="token number">10</span><span class="token punctuation">;</span> c<span class="token operator">++</span> <span class="token punctuation">))</span></span> </span><span class="code-line"><span class="token keyword">do</span> </span><span class="code-line"> <span class="token function">sleep</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token function">time</span> delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null </span><span class="code-line"><span class="token keyword">done</span> </span></code></pre></div><p>the result on a 6 core CPU, most of the execution cost &gt;= <code>100ms</code> :</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token comment"># this test run under a 6 core CPU machine</span> </span><span class="code-line">❯ <span class="token keyword">for</span> <span class="token variable"><span class="token punctuation">((</span> c<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">;</span> c<span class="token operator">&lt;=</span><span class="token number">10</span><span class="token punctuation">;</span> c<span class="token operator">++</span> <span class="token punctuation">))</span></span> </span><span class="code-line"><span class="token keyword">do</span> </span><span class="code-line"> <span class="token function">sleep</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token function">time</span> delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null </span><span class="code-line"><span class="token keyword">done</span> </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.00s system <span class="token number">62</span>% cpu <span class="token number">0.091</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.00s system <span class="token number">45</span>% cpu <span class="token number">0.122</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.00s system <span class="token number">41</span>% cpu <span class="token number">0.136</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.04s user <span class="token number">0</span>.01s system <span class="token number">52</span>% cpu <span class="token number">0.110</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">39</span>% cpu <span class="token number">0.142</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">45</span>% cpu <span class="token number">0.122</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.00s system <span class="token number">39</span>% cpu <span class="token number">0.143</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">46</span>% cpu <span class="token number">0.121</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">101</span>% cpu <span class="token number">0.055</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.00s system <span class="token number">40</span>% cpu <span class="token number">0.141</span> total </span></code></pre></div><p>in a benchmark situation, it is more like this (with out the <code>sleep</code>), yes, you may found that it is at low latency, about <code>50ms</code></p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token comment"># this test run under a 6 core CPU machine</span> </span><span class="code-line">❯ <span class="token keyword">for</span> <span class="token variable"><span class="token punctuation">((</span> c<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">;</span> c<span class="token operator">&lt;=</span><span class="token number">10</span><span class="token punctuation">;</span> c<span class="token operator">++</span> <span class="token punctuation">))</span></span> </span><span class="code-line"><span class="token keyword">do</span> </span><span class="code-line"> <span class="token function">time</span> delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null </span><span class="code-line"><span class="token keyword">done</span> </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">100</span>% cpu <span class="token number">0.055</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">101</span>% cpu <span class="token number">0.054</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.00s system <span class="token number">101</span>% cpu <span class="token number">0.055</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">100</span>% cpu <span class="token number">0.056</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">100</span>% cpu <span class="token number">0.055</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.04s user <span class="token number">0</span>.02s system <span class="token number">101</span>% cpu <span class="token number">0.055</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">90</span>% cpu <span class="token number">0.063</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.06s user <span class="token number">0</span>.00s system <span class="token number">85</span>% cpu <span class="token number">0.068</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.00s system <span class="token number">99</span>% cpu <span class="token number">0.058</span> total </span><span class="code-line">delta Cargo.toml Cargo.toml.bak <span class="token operator">&gt;</span> /dev/null <span class="token number">0</span>.05s user <span class="token number">0</span>.01s system <span class="token number">100</span>% cpu <span class="token number">0.055</span> total </span></code></pre></div><ol start="3"><li><p>使用开源工具遇到问题, 不要把全部的问题抛出给原作者, 有能力的情况下, 可以协助解决, 很多作者还是会热心回答和采纳的. 解决问题的过程中, 自己也能学到新的东西.</p></li><li><p>留下一个问题: 为什么获取单个核心 CPU 频率的系统调用 (通过读取 sysfs 触发的) 那么慢 (每个调用大概耗时在 <code>15ms</code> 以上)? 暂时没空看了, 文章先写到这吧.</p></li></ol><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://github.com/dandavison/delta/issues/839">https://github.com/dandavison/delta/issues/839</a></p><p><a href="https://github.com/dandavison/delta/issues/824">https://github.com/dandavison/delta/issues/824</a></p><p><a href="https://github.com/dandavison/delta/pull/845">https://github.com/dandavison/delta/pull/845</a></p><p><a href="https://github.com/GuillaumeGomez/sysinfo/issues/632">https://github.com/GuillaumeGomez/sysinfo/issues/632</a></p><p><a href="https://github.com/dandavison/delta/releases/tag/0.11.3">https://github.com/dandavison/delta/releases/tag/0.11.3</a></p> Mon, 20 Dec 2021 17:23:10 GMT ttyS3 rustlifetimetraitdebugprofileflamegraphdeltadiffsysinfo https://ttys3.dev/blog/rust-trait-lifetime-bounds Rust Trait Lifetime Bounds https://ttys3.dev/blog/rust-trait-lifetime-bounds <h2 id="提问的故事----废话哥-vs-高效哥"><a href="#提问的故事----废话哥-vs-高效哥" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>提问的故事 -- 废话哥 vs 高效哥</h2><p>起因我折腾的时候, 升级了 <code>zero-to-production</code> 这个仓库的 <code>tracing-bunyan-formatter</code> 版本,</p><p>它<a href="https://github.com/LukeMathWalker/zero-to-production/blob/42d4f6a024fda2e7bc277679a595e3edfa2cb6c9/src/telemetry.rs#L18">当前依赖</a>的是 0.2 版的 <code>tracing-bunyan-formatter</code> 和 <code>tracing-subscriber</code> :</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token property key">tracing-subscriber</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token property key">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.2.12&quot;</span><span class="token punctuation">,</span> <span class="token property key">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">&quot;registry&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;env-filter&quot;</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token property key">tracing-bunyan-formatter</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.2.2&quot;</span> </span></code></pre></div><p>但是由于 0.3 版的 <code>tracing-subscriber</code> 的 <code>MakeWriter</code> trait 签名改变了, 所以 0.3 版的 <code>tracing-bunyan-formatter</code> 的 <code>new</code> 方法的定义也改变了, 导致我直接编译不过.</p><p>0.2 的定义是这样的:</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function function-definition">get_subscriber</span><span class="token punctuation">(</span> </span><span class="code-line"> name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> </span><span class="code-line"> env_filter<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> </span><span class="code-line"> sink<span class="token punctuation">:</span> <span class="token keyword">impl</span> <span class="token class-name">MakeWriter</span> <span class="token operator">+</span> <span class="token class-name">Send</span> <span class="token operator">+</span> <span class="token class-name">Sync</span> <span class="token operator">+</span> <span class="token lifetime-annotation symbol">&#x27;static</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">impl</span> <span class="token class-name">Subscriber</span> <span class="token operator">+</span> <span class="token class-name">Sync</span> <span class="token operator">+</span> <span class="token class-name">Send</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> env_filter <span class="token operator">=</span> </span><span class="code-line"> <span class="token class-name">EnvFilter</span><span class="token punctuation">::</span><span class="token function">try_from_default_env</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap_or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>_<span class="token punctuation closure-punctuation">|</span></span> <span class="token class-name">EnvFilter</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>env_filter<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> formatting_layer <span class="token operator">=</span> <span class="token class-name">BunyanFormattingLayer</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> sink<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token class-name">Registry</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span>env_filter<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span><span class="token class-name">JsonStorageLayer</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span>formatting_layer<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>重点是这里的 <code>sink: impl MakeWriter + Send + Sync + &#x27;static</code></p><p>升级到 0.3 后就直接报错了:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">error<span class="token punctuation">[</span><span class="token constant">E0106</span><span class="token punctuation">]</span><span class="token operator">:</span> missing lifetime specifier </span><span class="code-line"> <span class="token operator">--</span><span class="token operator">&gt;</span> src<span class="token operator">/</span>telemetry<span class="token punctuation">.</span><span class="token property-access">rs</span><span class="token operator">:</span><span class="token number">18</span><span class="token operator">:</span><span class="token number">16</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">18</span> <span class="token operator">|</span> sink<span class="token operator">:</span> impl <span class="token maybe-class-name">MakeWriter</span> <span class="token operator">+</span> <span class="token maybe-class-name">Send</span> <span class="token operator">+</span> <span class="token maybe-class-name">Sync</span> <span class="token operator">+</span> &#x27;<span class="token keyword">static</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span> expected named lifetime parameter </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token property literal-property">help</span><span class="token operator">:</span> consider introducing a named lifetime parameter </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">15</span> <span class="token operator">~</span> pub fn get_subscriber<span class="token operator">&lt;</span>&#x27;a<span class="token operator">&gt;</span><span class="token punctuation">(</span> </span><span class="code-line"><span class="token number">16</span> <span class="token operator">|</span> name<span class="token operator">:</span> <span class="token class-name known-class-name">String</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token number">17</span> <span class="token operator">|</span> env_filter<span class="token operator">:</span> <span class="token class-name known-class-name">String</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token number">18</span> <span class="token operator">~</span> sink<span class="token operator">:</span> impl <span class="token maybe-class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token string">&#x27;a&gt; + Send + Sync + &#x27;</span><span class="token keyword">static</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"> </span><span class="code-line"><span class="token maybe-class-name">For</span> more information about <span class="token keyword">this</span> error<span class="token punctuation">,</span> <span class="token keyword control-flow">try</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">rustc --explain E0106</span><span class="token string template-punctuation">`</span></span><span class="token punctuation">.</span> </span><span class="code-line"><span class="token property literal-property">error</span><span class="token operator">:</span> could not compile <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">zero2prod</span><span class="token string template-punctuation">`</span></span> due to previous error </span></code></pre></div><p>这里的问题在于, 你如果一直试图按编译器的错误提示(tips)去修正错误, 是不可能完成这个fix的.</p><p>比如我按它上面的提示加个lifetime param <code>&lt;&#x27;a&gt;</code> :</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function function-definition">get_subscriber</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span><span class="token punctuation">(</span> </span><span class="code-line"> name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> </span><span class="code-line"> env_filter<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> </span><span class="code-line"> sink<span class="token punctuation">:</span> <span class="token keyword">impl</span> <span class="token class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span> <span class="token operator">+</span> <span class="token class-name">Send</span> <span class="token operator">+</span> <span class="token class-name">Sync</span> <span class="token operator">+</span> <span class="token lifetime-annotation symbol">&#x27;static</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">impl</span> <span class="token class-name">Subscriber</span> <span class="token operator">+</span> <span class="token class-name">Sync</span> <span class="token operator">+</span> <span class="token class-name">Send</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> env_filter <span class="token operator">=</span> </span><span class="code-line"> <span class="token class-name">EnvFilter</span><span class="token punctuation">::</span><span class="token function">try_from_default_env</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap_or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>_<span class="token punctuation closure-punctuation">|</span></span> <span class="token class-name">EnvFilter</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>env_filter<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> formatting_layer <span class="token operator">=</span> <span class="token class-name">BunyanFormattingLayer</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> sink<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token class-name">Registry</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span>env_filter<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span><span class="token class-name">JsonStorageLayer</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span>formatting_layer<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>然后你会发现这个报错越来越复杂了:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">❯ cargo check </span><span class="code-line"> <span class="token maybe-class-name">Checking</span> zero2prod v0<span class="token punctuation">.</span><span class="token number">1.0</span> <span class="token punctuation">(</span><span class="token operator">/</span>home<span class="token operator">/</span>ttys3<span class="token operator">/</span>repo<span class="token operator">/</span>rust<span class="token operator">/</span>zero<span class="token operator">-</span>to<span class="token operator">-</span>production<span class="token punctuation">)</span> </span><span class="code-line">error<span class="token punctuation">[</span><span class="token constant">E0277</span><span class="token punctuation">]</span><span class="token operator">:</span> expected a <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Fn&lt;()&gt;</span><span class="token string template-punctuation">`</span></span> closure<span class="token punctuation">,</span> found <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">--</span><span class="token operator">&gt;</span> src<span class="token operator">/</span>telemetry<span class="token punctuation">.</span><span class="token property-access">rs</span><span class="token operator">:</span><span class="token number">22</span><span class="token operator">:</span><span class="token number">61</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">22</span> <span class="token operator">|</span> <span class="token keyword">let</span> formatting_layer <span class="token operator">=</span> <span class="token maybe-class-name">BunyanFormattingLayer</span><span class="token operator">:</span><span class="token operator">:</span><span class="token keyword">new</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> sink<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span> <span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span> expected an <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Fn&lt;()&gt;</span><span class="token string template-punctuation">`</span></span> closure<span class="token punctuation">,</span> found <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">|</span> </span><span class="code-line"> <span class="token operator">|</span> required by a bound introduced by <span class="token keyword">this</span> call </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> wrap the <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> <span class="token keyword">in</span> a closure <span class="token keyword">with</span> no arguments<span class="token operator">:</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">|| { /* code */ }</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> required because <span class="token keyword">of</span> the requirements on the impl <span class="token keyword">of</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">for&lt;&#x27;a&gt; MakeWriter&lt;&#x27;a&gt;</span><span class="token string template-punctuation">`</span></span> <span class="token keyword control-flow">for</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"><span class="token property literal-property">note</span><span class="token operator">:</span> required by <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">BunyanFormattingLayer::&lt;W&gt;::new</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">--</span><span class="token operator">&gt;</span> <span class="token operator spread">...</span><span class="token operator">/</span>tracing<span class="token operator">-</span>bunyan<span class="token operator">-</span>formatter<span class="token operator">-</span><span class="token number">0.3</span><span class="token number">.1</span><span class="token operator">/</span>src<span class="token operator">/</span>formatting_layer<span class="token punctuation">.</span><span class="token property-access">rs</span><span class="token operator">:</span><span class="token number">71</span><span class="token operator">:</span><span class="token number">5</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">71</span> <span class="token operator">|</span> pub fn <span class="token keyword">new</span><span class="token punctuation">(</span>name<span class="token operator">:</span> <span class="token class-name known-class-name">String</span><span class="token punctuation">,</span> <span class="token property literal-property">make_writer</span><span class="token operator">:</span> <span class="token constant">W</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token maybe-class-name">Self</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span> </span><span class="code-line"><span class="token property literal-property">help</span><span class="token operator">:</span> consider further restricting <span class="token keyword">this</span> bound </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">18</span> <span class="token operator">|</span> sink<span class="token operator">:</span> impl <span class="token maybe-class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token string">&#x27;a&gt; + Send + Sync + &#x27;</span><span class="token keyword">static</span> <span class="token operator">+</span> std<span class="token operator">:</span><span class="token operator">:</span>ops<span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">Fn</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span> </span><span class="code-line"> </span><span class="code-line">error<span class="token punctuation">[</span><span class="token constant">E0277</span><span class="token punctuation">]</span><span class="token operator">:</span> expected a <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Fn&lt;()&gt;</span><span class="token string template-punctuation">`</span></span> closure<span class="token punctuation">,</span> found <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">--</span><span class="token operator">&gt;</span> src<span class="token operator">/</span>telemetry<span class="token punctuation">.</span><span class="token property-access">rs</span><span class="token operator">:</span><span class="token number">22</span><span class="token operator">:</span><span class="token number">28</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">22</span> <span class="token operator">|</span> <span class="token keyword">let</span> formatting_layer <span class="token operator">=</span> <span class="token maybe-class-name">BunyanFormattingLayer</span><span class="token operator">:</span><span class="token operator">:</span><span class="token keyword">new</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> sink<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span> expected an <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Fn&lt;()&gt;</span><span class="token string template-punctuation">`</span></span> closure<span class="token punctuation">,</span> found <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> wrap the <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> <span class="token keyword">in</span> a closure <span class="token keyword">with</span> no arguments<span class="token operator">:</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">|| { /* code */ }</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> required because <span class="token keyword">of</span> the requirements on the impl <span class="token keyword">of</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">for&lt;&#x27;a&gt; MakeWriter&lt;&#x27;a&gt;</span><span class="token string template-punctuation">`</span></span> <span class="token keyword control-flow">for</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"><span class="token property literal-property">note</span><span class="token operator">:</span> required by a bound <span class="token keyword">in</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">BunyanFormattingLayer</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">--</span><span class="token operator">&gt;</span> <span class="token operator spread">...</span><span class="token operator">/</span>tracing<span class="token operator">-</span>bunyan<span class="token operator">-</span>formatter<span class="token operator">-</span><span class="token number">0.3</span><span class="token number">.1</span><span class="token operator">/</span>src<span class="token operator">/</span>formatting_layer<span class="token punctuation">.</span><span class="token property-access">rs</span><span class="token operator">:</span><span class="token number">43</span><span class="token operator">:</span><span class="token number">37</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">43</span> <span class="token operator">|</span> pub struct <span class="token maybe-class-name">BunyanFormattingLayer</span><span class="token operator">&lt;</span><span class="token constant">W</span><span class="token operator">:</span> <span class="token keyword control-flow">for</span><span class="token operator">&lt;</span><span class="token string">&#x27;a&gt; MakeWriter&lt;&#x27;</span>a<span class="token operator">&gt;</span> <span class="token operator">+</span> &#x27;<span class="token keyword">static</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span> required by <span class="token keyword">this</span> bound <span class="token keyword">in</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">BunyanFormattingLayer</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"><span class="token property literal-property">help</span><span class="token operator">:</span> consider further restricting <span class="token keyword">this</span> bound </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">18</span> <span class="token operator">|</span> sink<span class="token operator">:</span> impl <span class="token maybe-class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token string">&#x27;a&gt; + Send + Sync + &#x27;</span><span class="token keyword">static</span> <span class="token operator">+</span> std<span class="token operator">:</span><span class="token operator">:</span>ops<span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">Fn</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span> </span><span class="code-line"> </span><span class="code-line">error<span class="token punctuation">[</span><span class="token constant">E0277</span><span class="token punctuation">]</span><span class="token operator">:</span> expected a <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Fn&lt;()&gt;</span><span class="token string template-punctuation">`</span></span> closure<span class="token punctuation">,</span> found <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">--</span><span class="token operator">&gt;</span> src<span class="token operator">/</span>telemetry<span class="token punctuation">.</span><span class="token property-access">rs</span><span class="token operator">:</span><span class="token number">26</span><span class="token operator">:</span><span class="token number">15</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">26</span> <span class="token operator">|</span> <span class="token punctuation">.</span><span class="token function property-access method">with</span><span class="token punctuation">(</span>formatting_layer<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">--</span><span class="token operator">--</span> <span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span> expected an <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Fn&lt;()&gt;</span><span class="token string template-punctuation">`</span></span> closure<span class="token punctuation">,</span> found <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">|</span> </span><span class="code-line"> <span class="token operator">|</span> required by a bound introduced by <span class="token keyword">this</span> call </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> wrap the <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> <span class="token keyword">in</span> a closure <span class="token keyword">with</span> no arguments<span class="token operator">:</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">|| { /* code */ }</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> required because <span class="token keyword">of</span> the requirements on the impl <span class="token keyword">of</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">for&lt;&#x27;a&gt; MakeWriter&lt;&#x27;a&gt;</span><span class="token string template-punctuation">`</span></span> <span class="token keyword control-flow">for</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> required because <span class="token keyword">of</span> the requirements on the impl <span class="token keyword">of</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">__tracing_subscriber_Layer&lt;Layered&lt;JsonStorageLayer, Layered&lt;EnvFilter, Registry&gt;&gt;&gt;</span><span class="token string template-punctuation">`</span></span> <span class="token keyword control-flow">for</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">BunyanFormattingLayer&lt;impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static&gt;</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"><span class="token property literal-property">help</span><span class="token operator">:</span> consider further restricting <span class="token keyword">this</span> bound </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">18</span> <span class="token operator">|</span> sink<span class="token operator">:</span> impl <span class="token maybe-class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token string">&#x27;a&gt; + Send + Sync + &#x27;</span><span class="token keyword">static</span> <span class="token operator">+</span> std<span class="token operator">:</span><span class="token operator">:</span>ops<span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">Fn</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span> </span><span class="code-line"> </span><span class="code-line">error<span class="token punctuation">[</span><span class="token constant">E0277</span><span class="token punctuation">]</span><span class="token operator">:</span> expected a <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Fn&lt;()&gt;</span><span class="token string template-punctuation">`</span></span> closure<span class="token punctuation">,</span> found <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">--</span><span class="token operator">&gt;</span> src<span class="token operator">/</span>telemetry<span class="token punctuation">.</span><span class="token property-access">rs</span><span class="token operator">:</span><span class="token number">19</span><span class="token operator">:</span><span class="token number">6</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">19</span> <span class="token operator">|</span> <span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> impl <span class="token maybe-class-name">Subscriber</span> <span class="token operator">+</span> <span class="token maybe-class-name">Sync</span> <span class="token operator">+</span> <span class="token maybe-class-name">Send</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span> expected an <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Fn&lt;()&gt;</span><span class="token string template-punctuation">`</span></span> closure<span class="token punctuation">,</span> found <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> wrap the <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> <span class="token keyword">in</span> a closure <span class="token keyword">with</span> no arguments<span class="token operator">:</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">|| { /* code */ }</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> required because <span class="token keyword">of</span> the requirements on the impl <span class="token keyword">of</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">for&lt;&#x27;a&gt; MakeWriter&lt;&#x27;a&gt;</span><span class="token string template-punctuation">`</span></span> <span class="token keyword control-flow">for</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> required because <span class="token keyword">of</span> the requirements on the impl <span class="token keyword">of</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">__tracing_subscriber_Layer&lt;Layered&lt;JsonStorageLayer, Layered&lt;EnvFilter, Registry&gt;&gt;&gt;</span><span class="token string template-punctuation">`</span></span> <span class="token keyword control-flow">for</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">BunyanFormattingLayer&lt;impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static&gt;</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> <span class="token operator">=</span> note<span class="token operator">:</span> required because <span class="token keyword">of</span> the requirements on the impl <span class="token keyword">of</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">tracing::Subscriber</span><span class="token string template-punctuation">`</span></span> <span class="token keyword control-flow">for</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">Layered&lt;BunyanFormattingLayer&lt;impl MakeWriter&lt;&#x27;a&gt; + Send + Sync + &#x27;static&gt;, Layered&lt;JsonStorageLayer, Layered&lt;EnvFilter, Registry&gt;&gt;&gt;</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"><span class="token property literal-property">help</span><span class="token operator">:</span> consider further restricting <span class="token keyword">this</span> bound </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">18</span> <span class="token operator">|</span> sink<span class="token operator">:</span> impl <span class="token maybe-class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token string">&#x27;a&gt; + Send + Sync + &#x27;</span><span class="token keyword">static</span> <span class="token operator">+</span> std<span class="token operator">:</span><span class="token operator">:</span>ops<span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">Fn</span><span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span><span class="token operator">++</span> </span><span class="code-line"> </span><span class="code-line"><span class="token maybe-class-name">For</span> more information about <span class="token keyword">this</span> error<span class="token punctuation">,</span> <span class="token keyword control-flow">try</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">rustc --explain E0277</span><span class="token string template-punctuation">`</span></span><span class="token punctuation">.</span> </span><span class="code-line"><span class="token property literal-property">error</span><span class="token operator">:</span> could not compile <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">zero2prod</span><span class="token string template-punctuation">`</span></span> due to <span class="token number">4</span> previous errors </span></code></pre></div><p>不能继续这样下去了, 继续按它的提示 tips 修改, 永远也无法修复这个问题.</p><p>于是我去作者的这本书(我购买了他的电子书)的Discord群里问, 结果一周了还没人回答出我要的答案. 其中有一个回答了, 说了一堆废话最后的意思是: 你应该坚持使用 0.2 版的.</p><p>我就感觉这个人有点搞笑了... 纯浪费时间. 此为 &quot;废话哥&quot;</p><p>然后突然有一天, 来了另一个哥们 (此为&quot;高效哥&quot;, &quot;快手&quot;-_-), 这哥们(不认识的 dude)二话不说直接把我拉进了一个 discoard thread, thread 标题也非常简单明了直接: &quot;fixing get_subscriber&quot;</p><p>这哥们直接说:</p><blockquote><p>&quot;<code>MakeWriter</code>现在需要一个<code>lifetime</code>我搞不定.&quot;</p><p>@asonix 好像上次更新这玩意是你弄的. 也许你可以帮我看下怎么搞定这个升级? 我无法弄明白怎么在这添加一个带lifetime的参数: <a href="https://github.com/LukeMathWalker/zero-to-production/blob/42d4f6a024fda2e7bc277679a595e3edfa2cb6c9/src/telemetry.rs#L18">https://github.com/LukeMathWalker/zero-to-production/blob/42d4f6a024fda2e7bc277679a595e3edfa2cb6c9/src/telemetry.rs#L18</a></p></blockquote><p>然后 asonix 这哥们居然很快现身了. 回答道:</p><blockquote><p>你可能需要放弃 <code>impl MakeWriter</code> 这种形式,转而使用泛型参数。 你需要 <code>for&lt;&#x27;a&gt; MakeWriter&lt;&#x27;a&gt;</code> 约束 所以你最终会得到</p></blockquote><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">fn</span> <span class="token function function-definition">my_fn</span><span class="token operator">&lt;</span><span class="token class-name">M</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>sink<span class="token punctuation">:</span> <span class="token class-name">M</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">impl</span> <span class="token class-name">Subscriber</span> </span><span class="code-line"><span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">M</span><span class="token punctuation">:</span> <span class="token keyword">for</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span> <span class="token class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span> <span class="token operator">+</span> <span class="token lifetime-annotation symbol">&#x27;static</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// ... </span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><blockquote><p>dude: &quot;Oh, wow, 多谢! 我还没在 Rust 里面用过这个 <code>for</code> 语法&quot;</p><p>asonix: 是的,for 语法有点奇怪,但它用于表示“对于任何给定的生命周期都是如此”,而不是将约束限制为特定的生命周期,这很有用</p></blockquote><p>最后, 这哥们 at 了一下我,</p><blockquote><p>&quot;来啦, 答案在这&quot;</p></blockquote><p>整个来回不超过6句话, 问题已经解决了.</p><p>于是我又回过头看 <a href="https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md#%E8%AF%9D%E4%B8%8D%E5%9C%A8%E5%A4%9A%E8%80%8C%E5%9C%A8%E7%B2%BE">&quot;提问的智慧&quot;</a></p><p>发现里面真的有一句 &quot;话不在多而在精&quot;.</p><p>所以, 其实这么多年了, 我还只掌握了这个文档的皮毛.</p><ol><li>我在提问的时候, 提供了过多的无关信息(错误日志, 上下文等), 从而导致人们不想看, 因为没人想看一堆乱七八糟的东西. 大家都喜欢简单.</li><li>我没有以&quot;最高效&quot; 的方式提问.</li></ol><p>这个哥们的提问为什么有如此高效的得到准确的答案? 原因是, 他是动过脑子的, 不是无脑地在群里直接提问. 而是有针对的 at 了相关作者.</p><p>比如这个例子里面, 使用到了 `tracing-bunyan-formatter 这个 crate, 通过一些基本的观察技能, 不难发现这个 commit 的作者正是 asonix:</p><p><a href="https://github.com/LukeMathWalker/tracing-bunyan-formatter/commit/7acebe58a5ae3079e938a9a0a6dab1a7b5226692">https://github.com/LukeMathWalker/tracing-bunyan-formatter/commit/7acebe58a5ae3079e938a9a0a6dab1a7b5226692</a></p><p>一般人喜欢用相同的昵称, 根据这一点, 这哥们直接在 discord 群里 at 了 asonix, 并且以建立 thread 的方式, 相当于单独拉小黑屋讨论了.</p><h2 id="为什么"><a href="#为什么" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>为什么?</h2><p>所以正确的参数是啥? 是这样:</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function function-definition">get_subscriber</span><span class="token operator">&lt;</span><span class="token class-name">W</span><span class="token operator">&gt;</span><span class="token punctuation">(</span> </span><span class="code-line"> name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> </span><span class="code-line"> env_filter<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> </span><span class="code-line"> sink<span class="token punctuation">:</span> <span class="token class-name">W</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">impl</span> <span class="token class-name">Subscriber</span> <span class="token operator">+</span> <span class="token class-name">Sync</span> <span class="token operator">+</span> <span class="token class-name">Send</span> </span><span class="code-line"> <span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">W</span><span class="token punctuation">:</span> <span class="token keyword">for</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span> <span class="token class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span> <span class="token operator">+</span> <span class="token class-name">Sync</span> <span class="token operator">+</span> <span class="token class-name">Send</span> <span class="token operator">+</span> <span class="token lifetime-annotation symbol">&#x27;static</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> env_filter <span class="token operator">=</span> </span><span class="code-line"> <span class="token class-name">EnvFilter</span><span class="token punctuation">::</span><span class="token function">try_from_default_env</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap_or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>_<span class="token punctuation closure-punctuation">|</span></span> <span class="token class-name">EnvFilter</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>env_filter<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> formatting_layer <span class="token operator">=</span> <span class="token class-name">BunyanFormattingLayer</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> sink<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token class-name">Registry</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span>env_filter<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span><span class="token class-name">JsonStorageLayer</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span>formatting_layer<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p><code>impl MakeWriter + Send + Sync + &#x27;static</code> 要换成泛型参数, 然后给泛型参数增加约束.</p><p>所以 <code>pub fn get_subscriber</code> 变成 <code>pub fn get_subscriber&lt;W&gt;</code></p><p><code>sink: impl MakeWriter + Send + Sync + &#x27;static</code> 变成 <code>sink: W</code>, 然后增加约束:</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"> <span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">W</span><span class="token punctuation">:</span> <span class="token keyword">for</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span> <span class="token class-name">MakeWriter</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span> <span class="token operator">+</span> <span class="token class-name">Sync</span> <span class="token operator">+</span> <span class="token class-name">Send</span> <span class="token operator">+</span> <span class="token lifetime-annotation symbol">&#x27;static</span> </span></code></pre></div><p>我们看下 <code>tracing-subscriber</code> crate <code>tracing_subscriber::fmt::MakeWriter</code> 这个 trait 的变化, 其实也能找到模式.</p><p>0.2 版的时候是这样:</p><p><a href="https://docs.rs/tracing-subscriber/0.2.25/tracing_subscriber/fmt/trait.MakeWriter.html">https://docs.rs/tracing-subscriber/0.2.25/tracing_subscriber/fmt/trait.MakeWriter.html</a></p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token class-name type-definition">MakeWriter</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">type</span> <span class="token class-name type-definition">Writer</span><span class="token punctuation">:</span> <span class="token class-name">Write</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">make_writer</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">Writer</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">make_writer_for</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> meta<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">Metadata</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;_</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">Writer</span> <span class="token punctuation">{</span> <span class="token punctuation">...</span> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>0.3 版就大变样了: <a href="https://docs.rs/tracing-subscriber/0.3.3/tracing_subscriber/fmt/trait.MakeWriter.html">https://docs.rs/tracing-subscriber/0.3.3/tracing_subscriber/fmt/trait.MakeWriter.html</a></p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">trait</span> <span class="token class-name type-definition">MakeWriter</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">type</span> <span class="token class-name type-definition">Writer</span><span class="token punctuation">:</span> <span class="token class-name">Write</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">make_writer</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">&#x27;a</span> <span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">Writer</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">make_writer_for</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">&#x27;a</span> <span class="token keyword">self</span><span class="token punctuation">,</span> meta<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">Metadata</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;_</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">Writer</span> <span class="token punctuation">{</span> <span class="token punctuation">...</span> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>那么, 原来的不是挺好的吗? 为什么要做这种改变?</p><p>我们去看一下 0.3.0 版的更新记录: <a href="https://github.com/tokio-rs/tracing/releases/tag/tracing-subscriber-0.3.0">https://github.com/tokio-rs/tracing/releases/tag/tracing-subscriber-0.3.0</a> 果然发现这么一条:</p><blockquote><p>fmt: Added a lifetime parameter to the <code>MakeWriter</code> trait, allowing it to return a borrowed writer. This enables implementations of <code>MakeWriter</code> for types such as <code>Mutex&lt;T: io::Write&gt;</code> and <code>std::fs::File</code>. (<a href="https://github.com/tokio-rs/tracing/pull/781">#781</a>)</p></blockquote><p>在 #781 <a href="https://github.com/tokio-rs/tracing/pull/781">https://github.com/tokio-rs/tracing/pull/781</a> 这个 PR 里面, 作者详细地解释了做这种 breaking change 的必要性.</p><h3 id="motivation"><a href="#motivation" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Motivation</h3><p>Currently, the <code>tracing-subscriber</code> crate has the <code>MakeWriter</code> trait for customizing the io writer used by <code>fmt</code>. This trait is necessary (rather than simply using a <code>Write</code> instance) because the default implementation performs the IO on the thread where an event was recorded, meaning that a separate writer needs to be acquired by each thread (either by calling a function like <code>io::stdout</code>, by locking a shared <code>Write</code> instance, etc).</p><p>Right now there is a blanket impl for <code>Fn() -&gt; T where T: Write</code>. This works fine with functions like <code>io::stdout</code>. However, the other common case for this trait is locking a shared writer.</p><p>Therefore, it makes sense to see an implementation like this:</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">impl</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token punctuation">,</span> <span class="token class-name">W</span><span class="token punctuation">:</span> <span class="token namespace">io<span class="token punctuation">::</span></span><span class="token class-name">Write</span><span class="token operator">&gt;</span> <span class="token class-name">MakeWriter</span> <span class="token keyword">for</span> <span class="token class-name">Mutex</span><span class="token operator">&lt;</span><span class="token class-name">W</span><span class="token operator">&gt;</span> </span><span class="code-line"><span class="token keyword">where</span> </span><span class="code-line"> <span class="token class-name">W</span><span class="token punctuation">:</span> <span class="token namespace">io<span class="token punctuation">::</span></span><span class="token class-name">Write</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">type</span> <span class="token class-name type-definition">Writer</span> <span class="token operator">=</span> <span class="token class-name">MutexWriter</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token punctuation">,</span> <span class="token class-name">W</span><span class="token operator">&gt;</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">make_writer</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">Writer</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name">MutexWriter</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token class-name type-definition">MutexWriter</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token punctuation">,</span> <span class="token class-name">W</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token class-name">MutexGuard</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;a</span><span class="token punctuation">,</span> <span class="token class-name">W</span><span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">impl</span><span class="token operator">&lt;</span><span class="token class-name">W</span><span class="token punctuation">:</span> <span class="token namespace">io<span class="token punctuation">::</span></span><span class="token class-name">Write</span><span class="token operator">&gt;</span> <span class="token namespace">io<span class="token punctuation">::</span></span><span class="token class-name">Write</span> <span class="token keyword">for</span> <span class="token class-name">MutexWriter</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">&#x27;_</span><span class="token punctuation">,</span> <span class="token class-name">W</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// write to the shared writer in the `MutexGuard`...</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>Unfortunately, it&#x27;s impossible to write this. Since <code>MakeWriter</code> always takes an <code>&amp;self</code> parameter and returns <code>Self::Writer</code>, the generic parameter is unbounded:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"> <span class="token maybe-class-name">Checking</span> tracing<span class="token operator">-</span>subscriber v0<span class="token punctuation">.</span><span class="token number">2.4</span> <span class="token punctuation">(</span><span class="token operator">/</span>home<span class="token operator">/</span>eliza<span class="token operator">/</span>code<span class="token operator">/</span>tracing<span class="token operator">/</span>tracing<span class="token operator">-</span>subscriber<span class="token punctuation">)</span> </span><span class="code-line">error<span class="token punctuation">[</span><span class="token constant">E0207</span><span class="token punctuation">]</span><span class="token operator">:</span> the lifetime parameter <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">&#x27;a</span><span class="token string template-punctuation">`</span></span> is not constrained by the impl trait<span class="token punctuation">,</span> self type<span class="token punctuation">,</span> or predicates </span><span class="code-line"> <span class="token operator">--</span><span class="token operator">&gt;</span> tracing<span class="token operator">-</span>subscriber<span class="token operator">/</span>src<span class="token operator">/</span>fmt<span class="token operator">/</span>writer<span class="token punctuation">.</span><span class="token property-access">rs</span><span class="token operator">:</span><span class="token number">61</span><span class="token operator">:</span><span class="token number">6</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"><span class="token number">61</span> <span class="token operator">|</span> impl<span class="token operator">&lt;</span>&#x27;a<span class="token punctuation">,</span> <span class="token constant">W</span><span class="token operator">:</span> io<span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">Write</span><span class="token operator">&gt;</span> <span class="token maybe-class-name">MakeWriter</span> <span class="token keyword control-flow">for</span> <span class="token maybe-class-name">Mutex</span><span class="token operator">&lt;</span><span class="token constant">W</span><span class="token operator">&gt;</span> </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">^</span><span class="token operator">^</span> unconstrained lifetime parameter </span><span class="code-line"> </span><span class="code-line"><span class="token property literal-property">error</span><span class="token operator">:</span> aborting due to previous error </span></code></pre></div><p>This essentially precludes any <code>MakeWriter</code> impl where the writer is borrowed from the type implementing <code>MakeWriter</code>. This is a significant blow to the usefulness of the trait. For example, it prevented the use of <code>MakeWriter</code> in <code>tracing-flame</code> as suggested in <a href="https://github.com/tokio-rs/tracing/pull/631#discussion_r391138233">#631</a> (comment).</p><h3 id="proposal"><a href="#proposal" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Proposal</h3><p>This PR changes <code>MakeWriter</code> to be generic over a lifetime <code>&#x27;a</code>:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">pub trait <span class="token maybe-class-name">MakeWriter</span><span class="token operator">&lt;</span>&#x27;a<span class="token operator">&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> type <span class="token maybe-class-name">Writer</span><span class="token operator">:</span> io<span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">Write</span><span class="token punctuation">;</span> </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">fn <span class="token function">make_writer</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>&#x27;a self<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token maybe-class-name">Self</span><span class="token operator">:</span><span class="token operator">:</span><span class="token maybe-class-name">Writer</span><span class="token punctuation">;</span> </span></code></pre></div><p>The <code>self</code> parameter is now borrowed for the <code>&amp;&#x27;a</code> lifetime, so it is okay to return a writer borrowed from <code>self</code>, such as in the <code>Mutex</code> case.</p><p>I&#x27;ve also added an impl of <code>MakeWriter</code> for <code>Mutex&lt;T&gt; where T: Writer</code>.</p><p>Unfortunately, this is a breaking change and will need to wait until we release <code>tracing-subscriber</code> 0.3.</p><p>Signed-off-by: Eliza Weisman</p><p>所以, 做这种破坏性变更的动机是, 实际实现这个trait的时候,遇到了一些麻烦, 比如当实现里面需要lifetime, 而 trait 定义本身并没有这个 lifetime 时, 编译通不地这.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://docs.rs/tracing-subscriber/0.2.25/tracing_subscriber/fmt/trait.MakeWriter.html">https://docs.rs/tracing-subscriber/0.2.25/tracing_subscriber/fmt/trait.MakeWriter.html</a></p><p><a href="https://docs.rs/tracing-subscriber/0.3.3/tracing_subscriber/fmt/trait.MakeWriter.html">https://docs.rs/tracing-subscriber/0.3.3/tracing_subscriber/fmt/trait.MakeWriter.html</a></p><p><a href="https://github.com/LukeMathWalker/tracing-bunyan-formatter/commit/7acebe58a5ae3079e938a9a0a6dab1a7b5226692">https://github.com/LukeMathWalker/tracing-bunyan-formatter/commit/7acebe58a5ae3079e938a9a0a6dab1a7b5226692</a></p><p><a href="https://github.com/LukeMathWalker/zero-to-production/blob/42d4f6a024fda2e7bc277679a595e3edfa2cb6c9/Cargo.toml#L28">https://github.com/LukeMathWalker/zero-to-production/blob/42d4f6a024fda2e7bc277679a595e3edfa2cb6c9/Cargo.toml#L28</a></p><p>Advanced Lifetimes <a href="https://doc.rust-lang.org/1.30.0/book/2018-edition/ch19-02-advanced-lifetimes.html#lifetime-bounds-on-references-to-generic-types">https://doc.rust-lang.org/1.30.0/book/2018-edition/ch19-02-advanced-lifetimes.html#lifetime-bounds-on-references-to-generic-types</a></p><p><a href="https://doc.rust-lang.org/rust-by-example/scope/lifetime/lifetime_bounds.html">https://doc.rust-lang.org/rust-by-example/scope/lifetime/lifetime_bounds.html</a></p><p><a href="https://doc.rust-lang.org/reference/trait-bounds.html">https://doc.rust-lang.org/reference/trait-bounds.html</a></p><p>The “Advanced Lifetimes” section in Chapter 19 was removed because compiler improvements have made the constructs in that section even rarer. <a href="https://doc.rust-lang.org/beta/book/title-page.html">https://doc.rust-lang.org/beta/book/title-page.html</a></p><p>--EOF</p> Mon, 20 Dec 2021 16:19:13 GMT ttyS3 rustlifetimetrait https://ttys3.dev/blog/lua-socket-imcompatbility-with-lua-543-and-the-fixup lua-socket imcompatbility with Lua 5.4.3 and the fixup https://ttys3.dev/blog/lua-socket-imcompatbility-with-lua-543-and-the-fixup <h2 id="the-problem"><a href="#the-problem" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>the problem</h2><p>lua 版本: <code>Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio</code></p><p>相关 issue <a href="https://github.com/diegonehab/luasocket/issues/331">HTTP calls do not work with lua 5.4.3 #331</a></p><p>报错:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">socket<span class="token operator">/</span>http<span class="token punctuation">.</span><span class="token property-access">lua</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span> bad argument #<span class="token number">1</span> to <span class="token string">&#x27;receive&#x27;</span> <span class="token punctuation">(</span>string expected<span class="token punctuation">,</span> got light userdata<span class="token punctuation">)</span> </span></code></pre></div><h2 id="the-solution"><a href="#the-solution" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>the solution</h2><p>有人已经提交一个 PR 了: <a href="https://github.com/diegonehab/luasocket/pull/334">https://github.com/diegonehab/luasocket/pull/334</a></p><p>根据这个 PR 的 review comment 来看, 貌似是这个提交漏改了一处: <a href="https://github.com/diegonehab/luasocket/commit/f329aae724573b87bd2a814f4858d29ca894600b">https://github.com/diegonehab/luasocket/commit/f329aae724573b87bd2a814f4858d29ca894600b</a></p><p>luarocks 其实是变相地支持从 git 仓库安装 rocks 的.</p><p>不过我测试 <code>luarocks install https://example.com/xxxx.spec</code> 失败了, 报的是网络问题, 但是实际上我用 curl 请求是成功的, 不太清楚原因. 因此只好把 spec 文件下载回来再 install.</p><p>拿 <a href="https://github.com/diegonehab/luasocket/blob/master/rockspec/luasocket-scm-2.rockspec">https://github.com/diegonehab/luasocket/blob/master/rockspec/luasocket-scm-2.rockspec</a> 修改一下:</p><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line">ersion <span class="token operator">=</span> <span class="token string">&quot;scm-3&quot;</span> </span><span class="code-line">source <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> url <span class="token operator">=</span> <span class="token string">&quot;git://github.com/pkulchenko/luasocket.git&quot;</span> </span><span class="code-line"> <span class="token punctuation">,</span> branch<span class="token operator">=</span><span class="token string">&quot;lua-543-aux-buffer-fix&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>我把修改后的结果直接放 gist 了, 安装:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token builtin class-name">cd</span> /tmp/ <span class="token operator">&amp;&amp;</span> <span class="token function">curl</span> <span class="token parameter variable">-LO</span> https://gist.github.com/ttys3/31dbf88ee7d708294d8ae5b0a4954424/raw/c74afc3edc1a48c0f7e1c2c9992750301bbb74ff/luasocket-scm-3.rockspec </span><span class="code-line">luarocks <span class="token function">install</span> ./luasocket-scm-3.rockspec </span></code></pre></div><p>这样安装成功后, 发现还是报同样的错. 然后发现是通过 pacman 安装了 <code>lua-socket</code> 包, 其优先级不知道为什么居然比我的 luarocks 的要高.</p><p>简单处理, 把系统的先卸载了吧, 看上去没啥其它东西依赖它:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">❯ ls <span class="token operator">/</span>usr<span class="token operator">/</span>lib<span class="token operator">/</span>lua<span class="token operator">/</span><span class="token number">5.4</span><span class="token operator">/</span>socket </span><span class="code-line"> core<span class="token punctuation">.</span><span class="token property-access">so</span>  serial<span class="token punctuation">.</span><span class="token property-access">so</span>  unix<span class="token punctuation">.</span><span class="token property-access">so</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">❯ paru <span class="token operator">-</span><span class="token constant">R</span> lua<span class="token operator">-</span>socket </span><span class="code-line">checking dependencies<span class="token operator spread">...</span> </span><span class="code-line"><span class="token literal-property property">error</span><span class="token operator">:</span> failed to prepare <span class="token function">transaction</span> <span class="token punctuation">(</span>could not satisfy dependencies<span class="token punctuation">)</span> </span><span class="code-line"><span class="token operator">:</span><span class="token operator">:</span> removing lua<span class="token operator">-</span>socket breaks dependency <span class="token string">&#x27;lua-socket&#x27;</span> required by lua<span class="token operator">-</span>copas </span><span class="code-line"><span class="token operator">:</span><span class="token operator">:</span> removing lua<span class="token operator">-</span>socket breaks dependency <span class="token string">&#x27;lua-socket&#x27;</span> required by lua<span class="token operator">-</span>sec </span><span class="code-line"> ☸ <span class="token function">homenas</span> <span class="token punctuation">(</span>tkn<span class="token operator">-</span>demo<span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token operator">~</span><span class="token operator">/</span><span class="token punctuation">.</span><span class="token property-access">luarocks</span> via  v5<span class="token punctuation">.</span><span class="token number">4.3</span> </span><span class="code-line">🔴 <span class="token number">1</span> ❯ paru <span class="token operator">-</span><span class="token constant">R</span> lua<span class="token operator">-</span>socket lua<span class="token operator">-</span>sec lua<span class="token operator">-</span>copas </span><span class="code-line">checking dependencies<span class="token operator spread">...</span> </span><span class="code-line"><span class="token operator">:</span><span class="token operator">:</span> luarocks optionally requires lua<span class="token operator">-</span>sec<span class="token operator">:</span> <span class="token constant">HTTPS</span> support </span><span class="code-line"> </span><span class="code-line"><span class="token function"><span class="token maybe-class-name">Package</span></span> <span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token maybe-class-name">Old</span> <span class="token maybe-class-name">Version</span> <span class="token maybe-class-name">Net</span> <span class="token maybe-class-name">Change</span> </span><span class="code-line"> </span><span class="code-line">lua<span class="token operator">-</span>copas <span class="token number">2.0</span><span class="token number">.2</span><span class="token operator">-</span><span class="token number">3</span> <span class="token operator">-</span><span class="token number">0.10</span> <span class="token maybe-class-name">MiB</span> </span><span class="code-line">lua<span class="token operator">-</span>sec <span class="token number">2</span><span class="token operator">:</span><span class="token number">1.0</span><span class="token number">.2</span><span class="token operator">-</span><span class="token number">1</span> <span class="token operator">-</span><span class="token number">0.19</span> <span class="token maybe-class-name">MiB</span> </span><span class="code-line">lua<span class="token operator">-</span>socket <span class="token number">20200329</span><span class="token operator">-</span><span class="token number">1</span> <span class="token operator">-</span><span class="token number">0.23</span> <span class="token maybe-class-name">MiB</span> </span><span class="code-line"> </span><span class="code-line"><span class="token maybe-class-name">Total</span> <span class="token maybe-class-name">Removed</span> <span class="token maybe-class-name">Size</span><span class="token operator">:</span> <span class="token number">0.52</span> <span class="token maybe-class-name">MiB</span> </span></code></pre></div><p>暂时来说, 问题解决. 等 <a href="https://github.com/diegonehab/luasocket">https://github.com/diegonehab/luasocket</a> 发新版本修复.</p><hr/><h2 id="what-is-light-userdata-"><a href="#what-is-light-userdata-" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>what is Light Userdata ?</h2><p><a href="https://www.lua.org/pil/28.5.html">https://www.lua.org/pil/28.5.html</a></p><p><a href="https://www.shouce.ren/api/lua/5/_161.htm">https://www.shouce.ren/api/lua/5/_161.htm</a></p><p>目前为止我们使用的userdata称为full userdata。Lua还提供了另一种userdata: light userdata。</p><p>一个light userdatum是一个表示C指针的值(也就是一个void *类型的值)。由于它是一个值,我们不能创建他们(同样的,我们也不能创建一个数字)。可以使用函数lua_pushlightuserdata将一个light userdatum入栈:</p><div class="relative"><pre><code class="code-highlight language-c"><span class="code-line"><span class="token keyword">void</span> <span class="token function">lua_pushlightuserdata</span> <span class="token punctuation">(</span>lua_State <span class="token operator">*</span>L<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>p<span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>尽管都是userdata,light userdata和full userdata有很大不同。Light userdata不是一个缓冲区,仅仅是一个指针,没有metatables。像数字一样,light userdata不需要垃圾收集器来管理她。</p><p>有些人把light userdata作为一个低代价的替代实现,来代替full userdata,但是这不是light userdata的典型应用。首先,使用light userdata你必须自己管理内存,因为他们和垃圾收集器无关。第二,尽管从名字上看有轻重之分,但full userdata实现的代价也并不大,比较而言,他只是在分配给定大小的内存时候,有一点点额外的代价。</p><p>Light userdata真正的用处在于可以表示不同类型的对象。当full userdata是一个对象的时候,它等于对象自身;另一方面,light userdata表示的是一个指向对象的指针,同样的,它等于指针指向的任何类型的userdata。所以,我们在Lua中使用light userdata表示C对象。</p><p>看一个典型的例子,假定我们要实现:Lua和窗口系统的绑定。这种情况下,我们使用full userdata表示窗口(每一个userdatum可以包含整个窗口结构或者一个有系统创建的指向单个窗口的指针)。当在窗口有一个事件发生(比如按下鼠标),系统会根据窗口的地址调用专门的回调函数。为了将这个回调函数传递给Lua,我们必须找到表示指定窗口的userdata。为了找到这个userdata,我们可以使用一个表:索引为表示窗口地址的light userdata,值为在Lua中表示窗口的full userdata。一旦我们有了窗口的地址,我们将窗口地址作为light userdata放到栈内,并且将userdata作为表的索引存到表内。(注意这个表应该有一个weak值,否则,这些full userdata永远不会被回收掉。)</p> Tue, 19 Oct 2021 20:54:26 GMT ttyS3 lualua-socketuserdatalight-userdata https://ttys3.dev/blog/openssh-8-8-p1-no-matching-host-key-type-found-their-offer-ssh-rsa Solution to openssh-8.8-p1 update: no matching host key type found. Their offer: ssh-rsa https://ttys3.dev/blog/openssh-8-8-p1-no-matching-host-key-type-found-their-offer-ssh-rsa <div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"> ~/.ssh </span><span class="code-line">❯ paru <span class="token variable parameter">-Ss</span> openssh <span class="token operator">|</span> rg <span class="token function">install</span> </span><span class="code-line">core/openssh <span class="token number">8</span>.8p1-1 <span class="token punctuation">[</span>0B <span class="token number">5</span>.90MiB<span class="token punctuation">]</span> <span class="token punctuation">[</span>Installed<span class="token punctuation">]</span> </span></code></pre></div><p>如果你最近升级到了 openssh 8.8-p1 版, 你会发现连接某些之前连接得好好的服务器突然无法连接:</p><blockquote><p>Unable to negotiate with x.x.x.x port 2222: no matching host key type found. Their offer: ssh-rsa</p></blockquote><p>解决办法</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">ssh</span> <span class="token variable parameter">-o</span> <span class="token variable assign-left">HostKeyAlgorithms</span><span class="token operator">=</span>+ssh-rsa <span class="token variable parameter">-o</span> <span class="token variable assign-left">PubkeyAcceptedKeyTypes</span><span class="token operator">=</span>+ssh-rsa user@myhost <span class="token variable parameter">-p</span> <span class="token number">2222</span> </span></code></pre></div><p>当然, 每次连接敲这么一长串也不太好.</p><p>编辑用户 ssh 配置 <code>~/.ssh/config</code>, 对于无法成功连接的host, 增加配置项:</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line"> HostKeyAlgorithms +ssh-rsa </span><span class="code-line"> PubkeyAcceptedKeyTypes +ssh-rsa </span></code></pre></div><p>完整的配置可能看起来像这样:</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line">Host myhost </span><span class="code-line"> Hostname 1.1.1.1 </span><span class="code-line"> User user001 </span><span class="code-line"> IdentityFile ~/.ssh/id_rsa </span><span class="code-line"> <span class="token comment"># fixup for openssh 8.8</span> </span><span class="code-line"> HostKeyAlgorithms +ssh-rsa </span><span class="code-line"> PubkeyAcceptedKeyTypes +ssh-rsa </span></code></pre></div><p>或者,像我一样的懒人:</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line">Host * </span><span class="code-line"> ServerAliveInterval 10 </span><span class="code-line"> HostKeyAlgorithms +ssh-rsa </span><span class="code-line"> PubkeyAcceptedKeyTypes +ssh-rsa </span></code></pre></div><h2 id="为什么会有这个错误"><a href="#为什么会有这个错误" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>为什么会有这个错误</h2><p>根据 <a href="http://www.openssh.com/">Open<strong>SSH</strong></a> Release Notes</p><p><strong>Future deprecation notice</strong></p><blockquote><p>It is now possible[1] to perform <strong>chosen-prefix attacks against the SHA-1 algorithm</strong> for less than USD$50K.</p><p>In the SSH protocol, the &quot;<strong>ssh-rsa</strong>&quot; signature scheme uses the SHA-1 hash algorithm in conjunction with the RSA public key algorithm. OpenSSH will disable this signature scheme by default in the near future.</p><p>Note that the deactivation of &quot;ssh-rsa&quot; signatures does not necessarily require cessation of use for RSA keys. In the SSH protocol, keys may be capable of signing using multiple algorithms. In particular, &quot;ssh-rsa&quot; keys are capable of signing using &quot;rsa-sha2-256&quot; (RSA/SHA256), &quot;rsa-sha2-512&quot; (RSA/SHA512) and &quot;ssh-rsa&quot; (RSA/SHA1). Only the last of these is being turned off by default.</p></blockquote><p>也就是说 8.8p1 版的 openssh 的 ssh 客户端默认禁用了 <code>ssh-rsa</code> 算法, 但是对方服务器只支持 <code>ssh-rsa</code>, 当你不能自己升级远程服务器的 openssh 版本或修改配置让它使用更安全的算法时, 在本地 ssh 针对这些旧的ssh server重新启用 <code>ssh-rsa</code> 也是一种权宜之法.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="http://www.openssh.com/releasenotes.html">http://www.openssh.com/releasenotes.html</a></p><p><a href="https://www.openssh.com/legacy.html">https://www.openssh.com/legacy.html</a></p> Mon, 27 Sep 2021 16:46:46 GMT ttyS3 opensshArchLinuxssh-rsatroubleshootssh https://ttys3.dev/blog/setup-caddy-as-php-fpm-reverse-proxy-server-with-one-line-config 用 caddy 代替 nginx, 一行配置搞定 php-fpm 反向代理 https://ttys3.dev/blog/setup-caddy-as-php-fpm-reverse-proxy-server-with-one-line-config <h2 id="缘由"><a href="#缘由" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h2><p>caddy 其实并不是一个新项目, 虽然早在 caddy 1.x 版本的时候老灯就关注这个项目了, 但是,老灯其实最近才开始去了解它和尝试使用它.</p><p>为什么之前一直没用 caddy 呢? 一是当时 nginx 还是非常坚挺, 可以说在 nginx + php-fpm 这一搭配方面, 基本上无敌手. 二是, 当时我试用过 Caddyfile 后,发现它太简洁了,简洁到我以配置 nginx 的思维, 完全无法适应配置 Caddyfile. 没错, 我当时觉得 , 配置 nginx 比 Caddyfile 简单多了 (因为 nginx 配置已经熟练多年).</p><p>从提交记录看, <a href="https://github.com/caddyserver/caddy/blob/v1/LICENSE.txt">https://github.com/caddyserver/caddy/blob/v1/LICENSE.txt</a> 最早可以追溯到2015年.</p><p>简单来说, Caddy 是一个使用 Golang 编写的 http 静态文件服务器和 反向代理服务器.</p><p>大概一年前,作者重构了 caddy, 也就是现在的 caddy 2.x 版. HN 上面依然可以找到他宣布 caddy 2 出来的消息:</p><blockquote><p>mholt on May 4, 2020 [–]</p><p>Hi HN -- this is what I&#x27;ve been working on for the last 14 months, with the help of many contributors and the backing of several sponsors. (Thank You!) Caddy 2 is a fresh new server experience. Some things might take getting used to, like having every site served over HTTPS unless you specify http:// explicitly in your config. But in general, it will feel familiar to v1 in a lot of ways. If you&#x27;ve used v1 before, I recommend going into v2 with a clean-slate using our Getting Started guide: <a href="https://caddyserver.com/docs/getting-started">https://caddyserver.com/docs/getting-started</a></p><p>I&#x27;m excited to finally get this out there. Let me know what questions you have!</p></blockquote><p>via <a href="https://news.ycombinator.com/item?id=23070567">https://news.ycombinator.com/item?id=23070567</a></p><p>那么, 为什么现在对 Caddy 感兴趣了?</p><p>一. 云原生</p><ol><li>单文件静态链接. 我在打包 PHP 应用的时候, 如果用 caddy, copy 一个文件即可. 不需要考虑各种动态链接和依赖.</li><li>自带 metrics ( <a href="https://caddyserver.com/docs/metrics">https://caddyserver.com/docs/metrics</a>)</li><li>自带 REST api (<a href="https://caddyserver.com/docs/api">https://caddyserver.com/docs/api</a>)</li></ol><p>二. 作为 Golang 程序员, 对于基于 Go 实现的东西, 有一种天生的好感.</p><h2 id="caddyfile-结构"><a href="#caddyfile-结构" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Caddyfile 结构</h2><p>下图取自官方文档: <a href="https://caddyserver.com/docs/caddyfile/concepts#structure">https://caddyserver.com/docs/caddyfile/concepts#structure</a></p><div><img alt="" src="https://ttys3.dev/static/assets/caddyfile-visual-KTAMOFT4.png" width="2960" height="1636"/></div><p>整个配置文件按块划分.</p><p>第一个红色的大 block 是全局配置块, 如果存在,它必须放在第一个块的位置.</p><p>每个 option 的配置, 基本上是 key - value 或者 key - list 的形式.</p><p>每个 snippet 也是单独成为一个 block, snippet 可以方便相同的配置复用,避免手动 copy 配置使得同样的配置分布在多处而难以维护.</p><p>每个站点单独成为一个 block.</p><p>这个配置足够简洁, 对于新手也极其友好.</p><p>关于配置这一块, 想要进一步了解的,可以查看官方文档, 同时推荐读一下 飞雪无情写的 <a href="https://www.flysnow.org/2021/09/05/caddy-in-action-caddyfile.html">Caddy实战(十一)| Caddyfile 设计之美</a></p><h2 id="配置-php-fpm-反向代理"><a href="#配置-php-fpm-反向代理" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>配置 php-fpm 反向代理</h2><p>从官方文档点击 &quot;<a href="https://caddyserver.com/docs/caddyfile/patterns">Common Patterns</a>&quot;, 然后其中就有<a href="https://caddyserver.com/docs/caddyfile/patterns#php">关于 PHP 的说明</a>.</p><p>配置一个 caddy + php-fpm 的博客, 全部指令如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">example.com </span><span class="code-line"> </span><span class="code-line">root * /var/www </span><span class="code-line">php_fastcgi /blog/* localhost:9000 </span><span class="code-line">file_server </span></code></pre></div><p><code>example.com</code>指定域名(默认监听<code>https</code>),</p><p><code>root * /var/www</code>指定站点根目录.</p><p><code>php_fastcgi /blog/* localhost:9000</code> 表示所有匹配 <code>/blog/*</code>的请求的 *.php 文件, 都被代理到 php-fpm 的监听地址 (<code>localhost:9000</code>)</p><p>如果要使用 unix socket 也是支持的, 将 <code>localhost:9000</code>替换成相应的 socket 地址即可, 如 <code>unix//run/php/php8.0-fpm.sock</code></p><p><code>file_server</code> 用于serve静态文件.</p><h2 id="404问题"><a href="#404问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>404问题</h2><p>没错, 上面的配置, 在大部分情况下是工作的. 对于现在一些基于<strong>流行 PHP 框架</strong>的应用, 比如 基于 Symfony / Laravel / CodeIgniter / CakePHP / Phalcon 等, 大多数是以<strong>单一入口</strong>来跑的. 对于<strong>单一入口的应用</strong>, 404 错误都是交给应用程序层面来处理的, 而不是 http 服务器.</p><p>对于非单一入口应用程序, 典型的是, 你手里有一个几年前的程序, 没有用任何框架, 这个时候, caddy 的默认配置, 404 的问题就出来了.</p><h3 id="the-problem"><a href="#the-problem" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>the problem</h3><p>这个问题直接描述比较抽象, 所以我这里举例子说明. 假设配置如下:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"># listen http and https both <span class="token keyword control-flow">for</span> example<span class="token punctuation">.</span><span class="token property-access">com</span> </span><span class="code-line"><span class="token punctuation">{</span>$<span class="token constant">SITE_ADDRESS</span><span class="token operator">:</span>http<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>example<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token punctuation">,</span> <span class="token literal-property property">https</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>example<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token punctuation">}</span> <span class="token punctuation">{</span> </span><span class="code-line"> root <span class="token operator">*</span> <span class="token operator">/</span>app<span class="token operator">/</span><span class="token keyword">public</span> </span><span class="code-line"> </span><span class="code-line"> # https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>caddyserver<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>docs<span class="token operator">/</span>caddyfile<span class="token operator">/</span>directives<span class="token operator">/</span>php_fastcgi </span><span class="code-line"> php_fastcgi <span class="token number">127.0</span><span class="token number">.0</span><span class="token number">.1</span><span class="token operator">:</span><span class="token number">9000</span> </span><span class="code-line"> </span><span class="code-line"> file_server </span><span class="code-line"> </span><span class="code-line"> handle_errors <span class="token punctuation">{</span> </span><span class="code-line"> root <span class="token operator">*</span> <span class="token operator">/</span>etc<span class="token operator">/</span>caddy<span class="token operator">/</span>error </span><span class="code-line"> rewrite <span class="token operator">*</span> <span class="token operator">/</span>error<span class="token punctuation">.</span><span class="token property-access">html</span> </span><span class="code-line"> templates </span><span class="code-line"> file_server </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>本意是, 如果有 404 或 403 等错误, 由 <code>/error.html</code>来处理, 但是实际上访问不存在的 url, 如</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token operator">/</span><span class="token keyword">this</span><span class="token operator">-</span>is<span class="token operator">-</span>not<span class="token operator">-</span>found<span class="token punctuation">.</span><span class="token property-access">html</span> </span><span class="code-line"><span class="token operator">/</span>blah<span class="token operator">-</span><span class="token keyword">this</span><span class="token operator">-</span>is<span class="token operator">-</span>another<span class="token operator">-</span>notfound<span class="token operator">/</span>xxxxxx </span><span class="code-line"><span class="token operator">/</span>xxxxxxx </span><span class="code-line"><span class="token operator">/</span>sub<span class="token operator">/</span>xxx<span class="token operator">/</span>sub<span class="token operator">/</span>xxxxx </span></code></pre></div><p>404 错误并没有发送给 <code>handle_errors</code> 这个 handler 来处理, 而是直接被 php index.php 处理了. 由于这个程序并不是单一入口应用, 因此它的 index.php 完全不知道如何错误 404 错误请求的 uri.</p><h3 id="尝试解决"><a href="#尝试解决" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>尝试解决</h3><p>然后我继续查看 Caddy 文档, 发现 <code>php_fastcgi</code> 有一个 <a href="https://caddyserver.com/docs/caddyfile/directives/php_fastcgi#expanded-form">Expanded form </a>, 我尝试把其中的 <code>try_files {path} {path}/index.php index.php</code> 修改为 <code>try_files {path} {path}/index.php</code> 之后,大部分 404 错误解决了. 但是以 .php 结尾的文件的 404 错误还是无法处理.</p><p>经过修改的完整的配置如下:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"># listen http and https both <span class="token keyword control-flow">for</span> example<span class="token punctuation">.</span><span class="token property-access">com</span> </span><span class="code-line"><span class="token punctuation">{</span>$<span class="token constant">SITE_ADDRESS</span><span class="token operator">:</span>http<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>example<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token punctuation">,</span> <span class="token literal-property property">https</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>example<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token punctuation">}</span> <span class="token punctuation">{</span> </span><span class="code-line"> root <span class="token operator">*</span> <span class="token operator">/</span>app<span class="token operator">/</span><span class="token keyword">public</span> </span><span class="code-line"> </span><span class="code-line"> # https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>caddyserver<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>docs<span class="token operator">/</span>caddyfile<span class="token operator">/</span>directives<span class="token operator">/</span>php_fastcgi </span><span class="code-line"> # php_fastcgi <span class="token number">127.0</span><span class="token number">.0</span><span class="token number">.1</span><span class="token operator">:</span><span class="token number">9000</span> </span><span class="code-line"> route <span class="token punctuation">{</span> </span><span class="code-line"> # <span class="token maybe-class-name">Add</span> trailing slash <span class="token keyword control-flow">for</span> directory requests </span><span class="code-line"> @canonicalPath <span class="token punctuation">{</span> </span><span class="code-line"> file <span class="token punctuation">{</span>path<span class="token punctuation">}</span><span class="token operator">/</span>index<span class="token punctuation">.</span><span class="token property-access">php</span> </span><span class="code-line"> not path <span class="token operator">*</span><span class="token operator">/</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> redir @canonicalPath <span class="token punctuation">{</span>path<span class="token punctuation">}</span><span class="token operator">/</span> <span class="token number">308</span> </span><span class="code-line"> </span><span class="code-line"> # <span class="token maybe-class-name">If</span> the requested file does not exist<span class="token punctuation">,</span> <span class="token keyword control-flow">try</span> index files </span><span class="code-line"> @indexFiles file <span class="token punctuation">{</span> </span><span class="code-line"> # try_files <span class="token punctuation">{</span>path<span class="token punctuation">}</span> <span class="token punctuation">{</span>path<span class="token punctuation">}</span><span class="token operator">/</span>index<span class="token punctuation">.</span><span class="token property-access">php</span> index<span class="token punctuation">.</span><span class="token property-access">php</span> </span><span class="code-line"> try_files <span class="token punctuation">{</span>path<span class="token punctuation">}</span> <span class="token punctuation">{</span>path<span class="token punctuation">}</span><span class="token operator">/</span>index<span class="token punctuation">.</span><span class="token property-access">php</span> </span><span class="code-line"> split_path <span class="token punctuation">.</span><span class="token property-access">php</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> rewrite @indexFiles <span class="token punctuation">{</span>http<span class="token punctuation">.</span><span class="token property-access">matchers</span><span class="token punctuation">.</span><span class="token property-access">file</span><span class="token punctuation">.</span><span class="token property-access">relative</span><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> # <span class="token class-name known-class-name">Proxy</span> <span class="token constant">PHP</span> files to the <span class="token maybe-class-name">FastCGI</span> responder </span><span class="code-line"> @phpFiles path <span class="token operator">*</span><span class="token punctuation">.</span><span class="token property-access">php</span> </span><span class="code-line"> reverse_proxy @phpFiles <span class="token number">127.0</span><span class="token number">.0</span><span class="token number">.1</span><span class="token operator">:</span><span class="token number">9000</span> <span class="token punctuation">{</span> </span><span class="code-line"> transport fastcgi <span class="token punctuation">{</span> </span><span class="code-line"> split <span class="token punctuation">.</span><span class="token property-access">php</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> file_server </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"> handle_errors <span class="token punctuation">{</span> </span><span class="code-line"> root <span class="token operator">*</span> <span class="token operator">/</span>etc<span class="token operator">/</span>caddy<span class="token operator">/</span>error </span><span class="code-line"> rewrite <span class="token operator">*</span> <span class="token operator">/</span>error<span class="token punctuation">.</span><span class="token property-access">html</span> </span><span class="code-line"> templates </span><span class="code-line"> file_server </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>目前这个配置还存在的问题, 无法处理 .php 结尾文件的 404 错误, 如</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token operator">/</span><span class="token keyword">this</span><span class="token operator">-</span>is<span class="token operator">-</span>no<span class="token operator">-</span>fount<span class="token punctuation">.</span><span class="token property-access">php</span> </span><span class="code-line"><span class="token operator">/</span>sub1<span class="token operator">/</span>sub2<span class="token operator">/</span>sub3<span class="token operator">/</span>xxxxx<span class="token punctuation">.</span><span class="token property-access">php</span> </span></code></pre></div><p>这种并不存在的 php 文件, 还是会被代理到 php-fpm 进程处理, 然后触发 php-fpm 响应 <strong>&quot; No input file specified. &quot;</strong> 的错误, 这个错误并不友好, 也不是我们期望的处理方式.</p><p>为了避免 <strong>&quot; No input file specified. &quot;</strong> 错误, 在 nginx 里面我们一般只需要这样处理:</p><div class="relative"><pre><code class="code-highlight language-nginx"><span class="code-line"> <span class="token comment"># Pass the php scripts to fastcgi server specified in upstream declaration.</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">location</span> ~ \.php(/|$)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment"># avoid No input file specified</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">try_files</span> <span class="token variable">$uri</span> =404</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">include</span> fastcgi_params</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment"># the missing param in fastcgi_params copied from fastcgi.conf</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">fastcgi_param</span> SCRIPT_FILENAME <span class="token variable">$document_root</span><span class="token variable">$fastcgi_script_name</span></span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">fastcgi_pass</span> 127.0.0.1:9000</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">fastcgi_buffer_size</span> <span class="token number">64k</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">fastcgi_buffers</span> <span class="token number">8</span> <span class="token number">256k</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">fastcgi_busy_buffers_size</span> <span class="token number">256k</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>没错, 神奇的地方就在于 <code>try_files $uri =404;</code> 这一行配置.</p><p>由于我其实等于是刚看了5分钟文档, 之前并没有真正使用 caddy, 因此我也不知道如何处理这一情况. 于是我把<a href="https://github.com/caddyserver/caddy/issues/4344">这个问题</a>发到 github 上面了.</p><p>然后其中一个热心开发者 <strong><a href="https://github.com/francislavoie">Francis Lavoie</a></strong> 马上给出了解决方案:</p><p><strong><a href="https://github.com/francislavoie">Francis Lavoie</a></strong> 觉得这是一个好问题. 他建议用一个 <a href="https://caddyserver.com/docs/caddyfile/directives/error">error</a> 指令来解决:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"># <span class="token maybe-class-name">Trigger</span> error <span class="token keyword control-flow">for</span> non<span class="token operator">-</span>existing <span class="token constant">PHP</span> scripts </span><span class="code-line">@phpNotFound <span class="token punctuation">{</span> </span><span class="code-line"> path <span class="token operator">*</span><span class="token punctuation">.</span><span class="token property-access">php</span> </span><span class="code-line"> not file </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line">error @phpNotFound <span class="token number">404</span> </span></code></pre></div><p>这样, 不存在的 php 文件就会触发 404 错误, 不会继续交给 php-fpm 处理.</p><h3 id="更好的实现方案"><a href="#更好的实现方案" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>更好的实现方案</h3><p>使用 <a href="https://caddyserver.com/docs/caddyfile/directives/error">error</a> 指令 加 <a href="https://caddyserver.com/docs/caddyfile/directives/php_fastcgi#expanded-form">Expanded form </a>确实能解决问题. 但是这是一个典型的应用场景, 应该还可以使配置更简化.</p><p>由于我对于 caddy 的代码并不了解,我的想法是&quot;解决问题&quot;, 所以我的理解是,简单地增加两个选项:</p><ol><li><p>always_proxy_to_index ( <code>try_files {path} {path}/index.php index.php</code> , off 的时候去掉最后面的 <code>index.php</code>)</p></li><li><p>pass_to_error_handler (遇到404等错误时,抛给其它 handler, 如 <code>handle_errors</code>)</p></li></ol><p>但是, <strong><a href="https://github.com/francislavoie">Francis Lavoie</a></strong> 的理解显然更加透彻, 他认为增加两个狭义的选项(使用场景非常有限), 容易使配置越来越复杂(后面要的功能更多,情况越复杂,这样的选项会越来越多). 于是便 有了这两个 PR</p><p>Add support for triggering errors from <code>try_files</code> #4346 <a href="https://github.com/caddyserver/caddy/pull/4346">https://github.com/caddyserver/caddy/pull/4346</a></p><p>Implement <code>try_files</code> override in Caddyfile directive #4347 <a href="https://github.com/caddyserver/caddy/pull/4347">https://github.com/caddyserver/caddy/pull/4347</a></p><p>大约一周过去了, 这两个 PR 都被  <a href="https://github.com/mholt">mholt</a> (caddy 创始人和主要开发者) review 并合并进去了.</p><p>第一个 PR 其实就是给 <code>try_files</code> 实现了 类似 nginx <code>=404</code> 这种功能.</p><p>第二个 PR 是允许对 <code>try_files</code> 进行 override. 这样 <code>php_fastcgi</code> 默认的<code>try_files</code> 就可以被自定义了.</p><p>这两个提交预计会在 caddy 2.5.0 版本发布.</p><p>到时候, 我的配置就可以简写为:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"># listen http and https both <span class="token keyword control-flow">for</span> example<span class="token punctuation">.</span><span class="token property-access">com</span> </span><span class="code-line"><span class="token punctuation">{</span>$<span class="token constant">SITE_ADDRESS</span><span class="token operator">:</span>http<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>example<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token punctuation">,</span> <span class="token literal-property property">https</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>example<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token punctuation">}</span> <span class="token punctuation">{</span> </span><span class="code-line"> root <span class="token operator">*</span> <span class="token operator">/</span>app<span class="token operator">/</span><span class="token keyword">public</span> </span><span class="code-line"> </span><span class="code-line"> # https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>caddyserver<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>docs<span class="token operator">/</span>caddyfile<span class="token operator">/</span>directives<span class="token operator">/</span>php_fastcgi </span><span class="code-line"> php_fastcgi localhost<span class="token operator">:</span><span class="token number">9000</span> <span class="token punctuation">{</span> </span><span class="code-line"> try_files <span class="token punctuation">{</span>path<span class="token punctuation">}</span> <span class="token punctuation">{</span>path<span class="token punctuation">}</span><span class="token operator">/</span>index<span class="token punctuation">.</span><span class="token property-access">php</span> <span class="token operator">=</span><span class="token number">404</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> file_server </span><span class="code-line"> </span><span class="code-line"> handle_errors <span class="token punctuation">{</span> </span><span class="code-line"> root <span class="token operator">*</span> <span class="token operator">/</span>etc<span class="token operator">/</span>caddy<span class="token operator">/</span>error </span><span class="code-line"> rewrite <span class="token operator">*</span> <span class="token operator">/</span>error<span class="token punctuation">.</span><span class="token property-access">html</span> </span><span class="code-line"> templates </span><span class="code-line"> file_server </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>不得不说, 这样实现, 使得整个配置变得更优雅. 功能增加了, 但是并没有增加新的配置指令和选项.</p><h2 id="思考"><a href="#思考" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>思考</h2><ol><li>使用开源产品时,遇到了问题,不要抱怨, 要有耐心,积极参与讨论.</li></ol><p>如果一个东西不完善, 并且你发现了这一点, 积极地提出来, 说不定开发者就采纳了, 改进了. 不单是你, 其它有同样需求的人也会受益.</p><ol start="2"><li>实现一个东西的时候, 不要只考虑解决当前问题而导致代码膨胀, 而是要看到问题的本质, 以更优雅地方式去解决.</li></ol><p>最后, 提一下, caddy 与 php 集成的时候, 还有一些性能优化相关的问题没解决, <a href="https://github.com/caddyserver/caddy/issues/3803">https://github.com/caddyserver/caddy/issues/3803</a></p> Mon, 20 Sep 2021 09:42:23 GMT ttyS3 caddyphpphp-fpmfpmnginxreverse-proxyhttp-server https://ttys3.dev/blog/failed-to-read-auto-increment-value-from-storage-engine #1467 - Failed to read auto-increment value from storage engine https://ttys3.dev/blog/failed-to-read-auto-increment-value-from-storage-engine <p>插入数据时自增id出错了</p><div class="relative"><pre><code class="language-sql code-highlight"><span class="code-line"><span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> <span class="token identifier"><span class="token punctuation">`</span>xxxx<span class="token punctuation">`</span></span> <span class="token punctuation">(</span><span class="token identifier"><span class="token punctuation">`</span>id<span class="token punctuation">`</span></span><span class="token punctuation">,</span> <span class="token identifier"><span class="token punctuation">`</span>name<span class="token punctuation">`</span></span><span class="token punctuation">,</span> <span class="token identifier"><span class="token punctuation">`</span>url<span class="token punctuation">`</span></span><span class="token punctuation">,</span> <span class="token identifier"><span class="token punctuation">`</span>info<span class="token punctuation">`</span></span><span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <span class="token punctuation">(</span><span class="token boolean">NULL</span><span class="token punctuation">,</span> <span class="token string">&#x27;blahblahblah&#x27;</span><span class="token punctuation">,</span> <span class="token string">&#x27;/xxxx&#x27;</span><span class="token punctuation">,</span> <span class="token string">&#x27;&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">#<span class="token number">1467</span> <span class="token operator">-</span> <span class="token maybe-class-name">Failed</span> to read auto<span class="token operator">-</span>increment value <span class="token keyword module">from</span> storage engine </span></code></pre></div><p>看看表的自增id现在是多少: ```SHOW CREATE TABLE xxxx`</p><div class="relative"><pre><code class="language-sql code-highlight"><span class="code-line"><span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token identifier"><span class="token punctuation">`</span>xxxx<span class="token punctuation">`</span></span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token identifier"><span class="token punctuation">`</span>id<span class="token punctuation">`</span></span> <span class="token keyword">tinyint</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token keyword">unsigned</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token identifier"><span class="token punctuation">`</span>name<span class="token punctuation">`</span></span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">128</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token string">&#x27;&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token identifier"><span class="token punctuation">`</span>url<span class="token punctuation">`</span></span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token string">&#x27;&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token identifier"><span class="token punctuation">`</span>info<span class="token punctuation">`</span></span> <span class="token keyword">varchar</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token keyword">DEFAULT</span> <span class="token string">&#x27;&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">(</span><span class="token identifier"><span class="token punctuation">`</span>id<span class="token punctuation">`</span></span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">)</span> <span class="token keyword">ENGINE</span><span class="token operator">=</span><span class="token keyword">InnoDB</span> <span class="token keyword">AUTO_INCREMENT</span><span class="token operator">=</span><span class="token number">18446744073709551615</span> <span class="token keyword">DEFAULT</span> <span class="token keyword">CHARSET</span><span class="token operator">=</span>utf8mb4 </span></code></pre></div><p>WTF ? <code>AUTO_INCREMENT=18446744073709551615</code>? AUTO_INCREMENT 的值已经爆掉了.</p><p>至于为什么爆掉了,原因不明. 有可能是以前从 MyISAM 转 InnoDB 的时候出问题了? 不清楚.</p><p>修正下表的自增id:</p><div class="relative"><pre><code class="language-sql code-highlight"><span class="code-line"><span class="token keyword">ALTER</span> <span class="token keyword">TABLE</span> <span class="token identifier"><span class="token punctuation">`</span>xxxx<span class="token punctuation">`</span></span> <span class="token keyword">AUTO_INCREMENT</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token keyword">SELECT</span> <span class="token function">MAX</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span> <span class="token keyword">FROM</span> xxxx<span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>然后再执行插入操作就行了.</p><p>Refs: <a href="https://stackoverflow.com/a/31557413/13267147">https://stackoverflow.com/a/31557413/13267147</a></p> Sat, 04 Sep 2021 09:36:20 GMT ttyS3 mysqlmariadb https://ttys3.dev/blog/what-kind-of-code-is-right-code 什么样的代码才算正确的? https://ttys3.dev/blog/what-kind-of-code-is-right-code <p>当然, 本来是不会有这篇文章的.</p><p>写这篇文章的原因, 非常复杂.</p><p>公司将团队沟通工具切换成了飞书 -&gt;</p><p>飞书没有 Linux 客户端 但是有 网页版 -&gt;</p><p>我下载了网上一个叫 electron-lark 的网页版飞书客户端 然后发现使用有些问题(跑个一天或几天不关, 会把桌面窗口的 title 全搞没了, 具体发生了什么我也没细看, 不开这个app就没事, 如果开了出现问题 alt + f2 然后按 r 重启 GNOME SHELL 也能恢复正常. 我尝试去修复这个问题, 比如关闭 electronjs 的硬件加速. 但是问题一直没有得到解决 -&gt;</p><p>我不得已自己开发了一个叫 lark-gtk 的同样是基于网页版飞书的客户端, webview 的主要实现基于 webkitgtk -&gt;</p><p>经过多次改版,这个 lark-gtk 终于功能稳定了. 但是有一项日常使用非常频繁的功能,没有办法工作: 那就是 ctrl + v 发送图片 (这个操作在 electron-lark 是完全没有问题的)-&gt;</p><p>经过一番研究,我发现这个问题其实是 webkitgtk 的 -&gt;</p><p>在某个夜黑风高的晚上, 我下载了当前使用版的 webkit 代码经过一番调试终于搞定了这个 ctrl + v 不工作的问题.</p><p>对于我来说, 其实问题就算解决了. 何不把它贡献给上游, 这样大家的问题都能得到解决? 提交给上游后,还有另一个好处, 你自己更新的时候再也不用自己编译了. 比如, 每次上游更新了代码, 你想要升级的时候, 你必须自己重新 patch 然后重新编译. 如果是普通的软件, 其实也无所谓, 但是 webkit 的代码, 编译一次大概是30分钟的样子, 确实还是有点费时间. (我的机器 CPU i9-9900 8c16t, RAM 32GB)</p><p>我知道我这个解决办法只能算是一个 workaround. but it works.</p><p>这么一个简单的 ctrl + v 的问题, 在 chromium 内核的所有浏览器里都不会存在的问题, 在 webkitgtk 存在多久了呢? 我也不清楚. 但是从 <a href="https://gitlab.gnome.org/GNOME/epiphany/-/issues/704">Can&#x27;t paste images from clipboard</a> 这个 issue 的创建时间 <code>Mar 23, 2019 5:57pm GMT+0800</code> 来看, 这个问题至少持久了两年以上了, 至今无人去解决.</p><p>所以, 我也真不知道这些开发大牛们都是去干嘛去了, 这么一个简单的功能, 但是又重要的功能, 没有给用户解决. 有人报告给了 GNOME (它家的 epiphany 浏览器是基于 webkitgtk 的), 然后 GNOME 那边的代表(来自 RedHat 的 Michael Catanzaro )说, 你应该报告给 webkit, 这是 webkit 的问题.</p><p>然后 Michael Catanzaro 指出一个链接 <a href="https://bugs.webkit.org/show_bug.cgi?id=177633">https://bugs.webkit.org/show_bug.cgi?id=177633</a> 这个链接其实是 Carlos Garcia Campos 给 GTK 版的适配 new Pasteboard API 的 patch. 这个 patch 提交发生在什么时候呢? <code>2020-05-16 05:11 PDT</code>, 也就是说, 即使没有 new Pasteboard API, 这个bug已经存在了. 在 Carlos Garcia Campos 适配 new Pasteboard API 后, 这个bug依旧存在. 到现在已经两年多了, 至今无人解决, 令我有点震惊, 开源项目现状就是这样? 还是 webkit 这样级别的开源项目?</p><p>我忐忑地将我这个蹩脚 patch 提交给了 webkit, 作为一个古老的项目, 提交 patch 的方式同样也相当古老.</p><p>首先我仔细阅读了两遍 <a href="https://webkit.org/contributing-code/">https://webkit.org/contributing-code/</a> 这个页面.</p><p>简单来说, 就是要提交 patch , 首先你要有一个 bug, 好在我已经找到一个别人提交好的 bug 了, 那就是</p><p><a href="https://bugs.webkit.org/show_bug.cgi?id=218519">https://bugs.webkit.org/show_bug.cgi?id=218519</a></p><p>提交 patch 后, GNOME 方面的 Michael Catanzaro (来自 RedHat) 回复了:</p><blockquote><p>I have no doubt that it works, but that can&#x27;t be the correct fix. readFilePathsFromClipboard should do what it says, not more. I haven&#x27;t looked closely, but you might be one level too far down from the right place to fix this.</p></blockquote><p>凭心而论, 他这回复也没什么毛病. 你这个 patch 虽然能修复问题, 能工作, 但是, 不应该这样来修.</p><p>毫无疑问, 这个 patch 肯定是会被 reject 的. 当然, 我并不是恼怒被拒, 而是有些失望, 一个简单的问题, 两年了还没人修. (为什么我能说是一个简单的问题? 因为我从来没看过 webkit 的代码, 加上几行 debug 日志, 编译两次之后, 也修复了这个问题. 只不过优雅的修复方法, 应该在其它地方加一些代码.)</p><p>我回复道:</p><blockquote><p>Thanks for the quick reply. I think you are right, this is not a correct fix.</p><p>I&#x27;m not familiar with the WebKit code at all. And I&#x27;m just a normal user which wait the correct patch for about 8 months or maybe longer.</p><p>I can not do further investigation to finish the right patch.</p><p>And hope someone will continue the work.</p><p>Thank you all guys.</p></blockquote><p>我的回复是完全实话实说的, 一来我确实没有多余的时间研究这个东西了, 我的要求很简单, 能稳定工作就行. 目前用自行patch后编译的版本已经能稳定工作了. 二来, 我确实不是浏览器引擎专家, 我对于 webkit 的了解完全建立在 Google 上. 这个问题应该交给专家们来修复.</p><p>我只是希望这些专家们能稍微加快一下进度 -_-</p><p>同时, 在专家们发布 &quot;the correct fix&quot; 之前, 我分享出我的 fixup, 其它有需要的人看到了, 也可以自取自用, 毕竟开源的东西还是有点好处, 你可以自己编译.</p><p>没错, 我只是一个普通的用户, just get me the fucking work done.</p><p>ctrl + v 是我每天要用的功能, 沟通的时候发图没有 ctrl + v 发送功能支持, 非常不方便.</p><p>发一个图的步骤变成了:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line">截图 <span class="operator token">-</span><span class="operator token">&gt;</span> 保存为文件 <span class="operator token">-</span><span class="operator token">&gt;</span> 打开文件 <span class="operator token">-</span><span class="operator token">&gt;</span> ctrl <span class="operator token">+</span> v </span></code></pre></div><p>如果 webkitgtk 没有这个 bug, 那么, 发一个图的步骤变成了正常操作:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line">截图 <span class="operator token">-</span><span class="operator token">&gt;</span> ctrl <span class="operator token">+</span> v </span></code></pre></div><p>然后我就思考了, 到底什么样的代码才算正确的?</p><p>显然, 对于开源项目来说, 需要维持代码的&quot;优雅&quot;, 一个bug宁可存在, 也不可引入不优雅的修复.</p><p>也就是, 正确的定义, 已经只局限在代码了. 代码正确就行, 管你能不能正常工作?</p><p>缺少这个功能,这是不支持,这是特性, 不是 bug.</p> Sun, 11 Jul 2021 15:07:16 GMT ttyS3 webkitgtkwebkitpatchpasteboardpasteclipboardgtkgnomeepiphany https://ttys3.dev/blog/leasing-routable-ip-addresses-with-podman-containers Leasing Routable IP Addresses with Podman Containers https://ttys3.dev/blog/leasing-routable-ip-addresses-with-podman-containers <p>Leasing routable IP addresses with Podman containers</p><p>图 &quot;Relic&quot; by BFS Man is licensed under CC BY 2.0</p><blockquote><p>Old Southern Pacific RR caboose sitting beside US 90 just east of Luling, TX. This was near another old railway car converted into a roadside diner, which had gone out of business. The &#x27;FOR LEASE&#x27; sign is actually for the diner, but I suppose the caboose comes with it.</p></blockquote><p>来自 <a href="https://www.flickr.com/photos/bfs_man/6265442738/in/photostream/">https://www.flickr.com/photos/bfs_man/6265442738/in/photostream/</a></p><p>本文主要是受 RedHat &quot;Leasing routable IP addresses with Podman containers&quot; 一文启发而写的. 配图也采用了原文章的.</p><p>其实标题的意思就是使用 macvlan 网络.</p><p>在一些特定场景中,比如一些传统应用或者监控应用需要直接使用 HOST 的物理网络,则可以使用 kernel 提供的 macvlan 的方式,macvlan 是在 HOST 网卡上创建多个子网卡,并分配独立的 IP 地址和 MAC 地址,把子网卡分配给容器实例来实现实例与物理网络的直通,并同时保持容器实例的隔离性。Host 收到数据包后,则根据不同的 MAC 地址把数据包从转发给不同的子接口,在外界来看就相当于多台主机。macvlan 要求物理网卡支持混杂 promisc 模式并且要求 kernel 为 v3.9-3.19 和 4.0+,因为是直接通过子接口转发数据包,所以可想而知,性能比 bridge 要高,不需要经过 NAT。</p><h2 id="创建-macvlan-类型的网络"><a href="#创建-macvlan-类型的网络" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>创建 macvlan 类型的网络</h2><p>在 podman 里面创建一个 macvlan 类型的网络, 可以使用如下命令:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">podman</span> network create <span class="token variable parameter">-d</span> macvlan <span class="token variable parameter">--macvlan</span> enp0s31f6 </span><span class="code-line"> </span><span class="code-line">/etc/cni/net.d/cni-podman1.conflist </span></code></pre></div><p><code>enp0s31f6</code> 是物理机的以太网口, 可以通过 <code>ip addr show</code> 找出来, 也可以通过 <code>nmcli</code> 比如:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ nmcli connect </span><span class="code-line">NAME UUID TYPE DEVICE </span><span class="code-line">Wired connection <span class="token number">1</span> 5b263355-a1ee-3aa5-b34d-c36eb142a04c ethernet enp0s31f6 </span><span class="code-line">cni-podman0 bf710dcd-26b5-47ec-ac99-53673fef2c27 bridge cni-podman0 </span><span class="code-line">docker0 dff45e06-a6e5-4510-a636-255f3f00d55c bridge docker0 </span><span class="code-line">virbr0 be3e2c28-1028-41f7-bfdc-1aed730a59e7 bridge virbr0 </span></code></pre></div><p>可以看到, podman 实际上是使用的 CNI 配置.</p><h2 id="什么是-cni"><a href="#什么是-cni" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>什么是 CNI</h2><blockquote><p>Container Network Interface - networking for Linux containers</p></blockquote><p>CNI 的仓库历史已经有 6 年之久了. 目前 CNI 是一个 CNCF 项目, 主要被 k8s 等应用.</p><p>同时, CNI 自己维护了一些核心插件,放在独立的仓库: <a href="https://github.com/containernetworking/plugins">https://github.com/containernetworking/plugins</a></p><p>CNI 核心插件主要包含:</p><h2 id="plugins-supplied"><a href="#plugins-supplied" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Plugins supplied:</h2><h3 id="main-interface-creating"><a href="#main-interface-creating" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Main: interface-creating</h3><ul><li><code>bridge</code>: Creates a bridge, adds the host and the container to it.</li><li><code>ipvlan</code>: Adds an <a href="https://www.kernel.org/doc/Documentation/networking/ipvlan.txt">ipvlan</a> interface in the container.</li><li><code>loopback</code>: Set the state of loopback interface to up.</li><li><code>macvlan</code>: Creates a new MAC address, forwards all traffic to that to the container.</li><li><code>ptp</code>: Creates a veth pair.</li><li><code>vlan</code>: Allocates a vlan device.</li><li><code>host-device</code>: Move an already-existing device into a container.</li></ul><h4 id="windows-windows-specific"><a href="#windows-windows-specific" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Windows: Windows specific</h4><ul><li><code>win-bridge</code>: Creates a bridge, adds the host and the container to it.</li><li><code>win-overlay</code>: Creates an overlay interface to the container.</li></ul><h3 id="ipam-ip-address-allocation"><a href="#ipam-ip-address-allocation" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>IPAM: IP address allocation</h3><ul><li><code>dhcp</code>: Runs a daemon on the host to make DHCP requests on behalf of the container</li><li><code>host-local</code>: Maintains a local database of allocated IPs</li><li><code>static</code>: Allocate a static IPv4/IPv6 addresses to container and it&#x27;s useful in debugging purpose.</li></ul><h3 id="meta-other-plugins"><a href="#meta-other-plugins" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Meta: other plugins</h3><ul><li><code>tuning</code>: Tweaks sysctl parameters of an existing interface</li><li><code>portmap</code>: An iptables-based portmapping plugin. Maps ports from the host&#x27;s address space to the container.</li><li><code>bandwidth</code>: Allows bandwidth-limiting through use of traffic control tbf (ingress/egress).</li><li><code>sbr</code>: A plugin that configures source based routing for an interface (from which it is chained).</li><li><code>firewall</code>: A firewall plugin which uses iptables or firewalld to add rules to allow traffic to/from the container.</li></ul><h3 id="sample"><a href="#sample" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Sample</h3><p>The sample plugin provides an example for building your own plugin.</p><p>我们这里用到的主要是 <code>macvlan</code> (属于接口创建类的插件) 和 <code>dhcp</code> (属于 IPAM 类的插件).</p><p>IPAM 即 IP address allocation 的缩写, 即 IP 地址分配. 工作是分离的, 即接口创建 和 接口 IP 分配 由不同的插件完成.</p><p>好了, 我们来看一下 podman 创建的 CNI 配置吧.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"> ~ </span><span class="code-line">❯ bat /etc/cni/net.d/cni-podman1.conflist </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;cniVersion&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;0.4.0&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;name&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;cni-podman1&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;plugins&quot;</span><span class="token builtin class-name">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;type&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;macvlan&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;master&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;enp0s31f6&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;ipam&quot;</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;type&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;dhcp&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span></code></pre></div><p>没错, RedHat 的人写那个文章的时候, <code>podman network</code> 还没有创建 <code>macvlan</code> 的支持, 因此需要手动创建 CNI 配置. 老灯现在用的 podman 版本较新, 创建 macvlan 还是比较方便了:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"> ~ </span><span class="code-line">❯ <span class="token function">sudo</span> <span class="token function">podman</span> version </span><span class="code-line">Version: <span class="token number">3.2</span>.2 </span><span class="code-line">API Version: <span class="token number">3.2</span>.2 </span><span class="code-line">Go Version: go1.16.5 </span><span class="code-line">Git Commit: d577c44e359f9f8284b38cf984f939b3020badc3 </span><span class="code-line">Built: Fri Jul <span class="token number">9</span> <span class="token number">20</span>:54:04 <span class="token number">2021</span> </span><span class="code-line">OS/Arch: linux/amd64 </span></code></pre></div><p>可以使用 <code>inspect</code> 查看一个网络的配置, 其实内容跟查看原生的 CNI 配置文件差不多:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"> ~ </span><span class="code-line">❯ <span class="token function">sudo</span> <span class="token function">podman</span> network inspect cni-podman1 </span><span class="code-line"><span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;cniVersion&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;0.4.0&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;name&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;cni-podman1&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;plugins&quot;</span><span class="token builtin class-name">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;ipam&quot;</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;type&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;dhcp&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span>, </span><span class="code-line"> <span class="token string">&quot;master&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;enp0s31f6&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;type&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;macvlan&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">]</span> </span></code></pre></div><p>首先, 这是一个 <code>.conflist</code> 的配置, 说明里面是有多个配置的 (plugins 里面是个数组). 但是这里其实只有一个配置([]里的第一层花括号), 这个配置有3个key: <code>ipam</code>, <code>master</code> 和 <code>type</code>. 所以主要的插件是 <code>macvlan</code>, 但是其实还依赖了 <code>dhcp</code> 插件.</p><p>使用 <code>podman network ls</code> 可以列出当前可用网络:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> <span class="token function">podman</span> network <span class="token function">ls</span> </span><span class="code-line">NETWORK ID NAME VERSION PLUGINS </span><span class="code-line">2f259bab93aa <span class="token function">podman</span> <span class="token number">0.4</span>.0 bridge,portmap,dnsname,firewall,tuning </span><span class="code-line">95eef1959fbc macvlan001 <span class="token number">0.4</span>.0 macvlan </span><span class="code-line">b932778640d3 cni-podman1 <span class="token number">0.4</span>.0 macvlan </span></code></pre></div><p><code>cni-podman1</code> 是刚才通过命令创建的, <code>macvlan001</code> 是我之前手动编写 CNI 配置文件创建的.</p><h2 id="使用-macvlan-创建容器"><a href="#使用-macvlan-创建容器" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>使用 macvlan 创建容器</h2><p>创建容器时指定网络为我们刚才创建的 <code>cni-podman1</code> 即可.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> <span class="token function">podman</span> run <span class="token variable parameter">-it</span> <span class="token variable parameter">--rm</span> <span class="token variable parameter">--network</span> cni-podman1 docker.io/library/alpine <span class="token function">sh</span> </span><span class="code-line">/ <span class="token comment"># ip a</span> </span><span class="code-line"><span class="token number">1</span>: lo: <span class="token operator">&lt;</span>LOOPBACK,UP,LOWER_UP<span class="token operator">&gt;</span> mtu <span class="token number">65536</span> qdisc noqueue state UNKNOWN qlen <span class="token number">1000</span> </span><span class="code-line"> link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 </span><span class="code-line"> inet <span class="token number">127.0</span>.0.1/8 scope <span class="token function">host</span> lo </span><span class="code-line"> valid_lft forever preferred_lft forever </span><span class="code-line"> inet6 ::1/128 scope <span class="token function">host</span> </span><span class="code-line"> valid_lft forever preferred_lft forever </span><span class="code-line"><span class="token number">2</span>: eth0@eth0: <span class="token operator">&lt;</span>BROADCAST,MULTICAST,UP,LOWER_UP<span class="token operator">&gt;</span> mtu <span class="token number">1500</span> qdisc noqueue state UP </span><span class="code-line"> link/ether 5a:cf:de:c3:0a:27 brd ff:ff:ff:ff:ff:ff </span><span class="code-line"> inet <span class="token number">192.168</span>.8.51/24 brd <span class="token number">192.168</span>.8.255 scope global eth0 </span><span class="code-line"> valid_lft forever preferred_lft forever </span><span class="code-line"> inet6 fe80::58cf:deff:fec3:a27/64 scope <span class="token function">link</span> </span><span class="code-line"> valid_lft forever preferred_lft forever </span><span class="code-line">/ <span class="token comment"># ping -c4 192.168.8.123</span> </span><span class="code-line">PING <span class="token number">192.168</span>.8.123 <span class="token punctuation">(</span><span class="token number">192.168</span>.8.123<span class="token punctuation">)</span>: <span class="token number">56</span> data bytes </span><span class="code-line"><span class="token number">64</span> bytes from <span class="token number">192.168</span>.8.123: <span class="token variable assign-left">seq</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">ttl</span><span class="token operator">=</span><span class="token number">42</span> <span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token number">0.186</span> ms </span><span class="code-line"><span class="token number">64</span> bytes from <span class="token number">192.168</span>.8.123: <span class="token variable assign-left">seq</span><span class="token operator">=</span><span class="token number">1</span> <span class="token variable assign-left">ttl</span><span class="token operator">=</span><span class="token number">42</span> <span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token number">0.267</span> ms </span><span class="code-line"><span class="token number">64</span> bytes from <span class="token number">192.168</span>.8.123: <span class="token variable assign-left">seq</span><span class="token operator">=</span><span class="token number">2</span> <span class="token variable assign-left">ttl</span><span class="token operator">=</span><span class="token number">42</span> <span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token number">0.323</span> ms </span><span class="code-line"><span class="token number">64</span> bytes from <span class="token number">192.168</span>.8.123: <span class="token variable assign-left">seq</span><span class="token operator">=</span><span class="token number">3</span> <span class="token variable assign-left">ttl</span><span class="token operator">=</span><span class="token number">42</span> <span class="token variable assign-left">time</span><span class="token operator">=</span><span class="token number">0.282</span> ms </span><span class="code-line"> </span><span class="code-line">--- <span class="token number">192.168</span>.8.123 <span class="token function">ping</span> statistics --- </span><span class="code-line"><span class="token number">4</span> packets transmitted, <span class="token number">4</span> packets received, <span class="token number">0</span>% packet loss </span><span class="code-line">round-trip min/avg/max <span class="token operator">=</span> <span class="token number">0.186</span>/0.264/0.323 ms </span><span class="code-line">/ <span class="token comment"># </span> </span><span class="code-line"> </span></code></pre></div><p>然后我们可以发现这个容器被分配了一个 <code>192.168.8.51</code> 的 IP, 这个网段与 host 机处在同一个网段. 通过路由器的 dhcp server 可以看到这个地址被分配了.</p><p>我们可以直接 ping 通同一网段里的其它主机, 比如上面的 <code>192.168.8.123</code>,同时,从同一局域网的其它主机可以 ping 通这个地址:</p><div class="remark-code-title">//yangjunsss.github.io/2018-07-29/Docker-%E7%BD%91%E7%BB%9C-Host-Bridge-Macvlan-%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%E5%92%8C%E9%AA%8C%E8%AF%81/</div><div class="relative"><pre><code class="code-highlight language-shellhttp"><span class="code-line">❯ ssh [email protected] </span><span class="code-line">Warning: Permanently added &#x27;192.168.8.123&#x27; (ED25519) to the list of known hosts. </span><span class="code-line">Activate the web console with: systemctl enable --now cockpit.socket </span><span class="code-line"> </span><span class="code-line">Last login: Fri Jul 9 21:07:11 2021 from 192.168.8.100 </span><span class="code-line"> root in homenas in ~ </span><span class="code-line">❯ ping 192.168.8.51 </span><span class="code-line">PING 192.168.8.51 (192.168.8.51) 56(84) bytes of data. </span><span class="code-line">64 bytes from 192.168.8.51: icmp_seq=1 ttl=64 time=0.456 ms </span><span class="code-line">64 bytes from 192.168.8.51: icmp_seq=2 ttl=64 time=0.227 ms </span><span class="code-line">64 bytes from 192.168.8.51: icmp_seq=3 ttl=64 time=0.249 ms </span><span class="code-line">64 bytes from 192.168.8.51: icmp_seq=4 ttl=64 time=0.180 ms </span><span class="code-line">^C </span><span class="code-line">--- 192.168.8.51 ping statistics --- </span><span class="code-line">4 packets transmitted, 4 received, 0% packet loss, time 3105ms </span><span class="code-line">rtt min/avg/max/mdev = 0.180/0.278/0.456/0.105 ms </span></code></pre></div><p>注意: 从本机是无法 ping 通这个地址的,这是 macvlan 的限制.</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"> ~ took 23s </span><span class="code-line">❯ <span class="token function">ping</span> <span class="token number">192.168</span>.8.51 </span><span class="code-line">PING <span class="token number">192.168</span>.8.51 <span class="token punctuation">(</span><span class="token number">192.168</span>.8.51<span class="token punctuation">)</span> <span class="token number">56</span><span class="token punctuation">(</span><span class="token number">84</span><span class="token punctuation">)</span> bytes of data. </span><span class="code-line">From <span class="token number">192.168</span>.8.100 <span class="token variable assign-left">icmp_seq</span><span class="token operator">=</span><span class="token number">1</span> Destination Host Unreachable </span><span class="code-line">From <span class="token number">192.168</span>.8.100 <span class="token variable assign-left">icmp_seq</span><span class="token operator">=</span><span class="token number">2</span> Destination Host Unreachable </span><span class="code-line">From <span class="token number">192.168</span>.8.100 <span class="token variable assign-left">icmp_seq</span><span class="token operator">=</span><span class="token number">3</span> Destination Host Unreachable </span><span class="code-line">^C </span><span class="code-line">--- <span class="token number">192.168</span>.8.51 <span class="token function">ping</span> statistics --- </span><span class="code-line"><span class="token number">5</span> packets transmitted, <span class="token number">0</span> received, +3 errors, <span class="token number">100</span>% packet loss, <span class="token function">time</span> 4066ms </span><span class="code-line">pipe <span class="token number">3</span> </span></code></pre></div><h2 id="macvlan-的四种通信模式"><a href="#macvlan-的四种通信模式" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>macvlan 的四种通信模式</h2><p>有一个配置选项,刚才 podman 里面并没有展示出来, 那就是 macvlan 插件有一个可选的 <code>mode</code> 参数, 默认值是 <code>bridge</code></p><blockquote><p>mode (string, optional): one of “bridge”, “private”, “vepa”, “passthru”. Defaults to “bridge”. (<a href="https://www.cni.dev/plugins/current/main/macvlan/#network-configuration-reference">https://www.cni.dev/plugins/current/main/macvlan/#network-configuration-reference</a>)</p></blockquote><p>macvlan 是一种网卡虚拟化技术,能够将一张网卡虚拟出多张网卡。</p><p>macvlan 的四种通信模式,常用模式是 bridge。</p><p>macvlan 支持四种模式:</p><ul><li><p>private:子接口之间不允许通信,子接口能与物理网络通讯,所有数据包都经过父接口 eth0</p></li><li><p>vepa(Virtual Ethernet Port Aggregator):子接口之间、子接口与物理网络允许通讯,数据包都经过 eth0 进出,要求交换机支持 IEEE 802.1Q。</p></li><li><p>bridge:子接口之间直接通讯,不经过父接口 eth0 ,性能较高,但是父接口 down 之后也同样丧失通讯能力。</p></li><li><p>passthru:Allows a single VM to be connected directly to the physical interface. The advantage of this mode is that VM is then able to change MAC address and other interface parameters.</p></li></ul><p>所有模式都不能与 父接口 eth0 通信,并且 macvlan 在公有云上的支持并不友好。</p><h2 id="应用"><a href="#应用" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>应用</h2><p>macvlan 这种网络模式一般在云平台都会被限制, 因此大部分情况下应该是有直接操作物理 host 机权限的时候才可以使用这种模式.</p><p>由于 IP 是可路由的, 因此非常适合用来做一些路由器相关的事情. 比如跑一个 openwrt 容器等.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p>本文主要参考: <a href="https://www.redhat.com/sysadmin/leasing-ips-podman">https://www.redhat.com/sysadmin/leasing-ips-podman</a></p><p><a href="https://github.com/containernetworking/cni">https://github.com/containernetworking/cni</a></p><p><a href="https://github.com/containernetworking/plugins">https://github.com/containernetworking/plugins</a></p><p><a href="https://www.cni.dev/plugins/current/main/macvlan/">https://www.cni.dev/plugins/current/main/macvlan/</a></p><p><a href="https://www.cni.dev/plugins/current/ipam/dhcp/">https://www.cni.dev/plugins/current/ipam/dhcp/</a></p><p><a href="https://docs.docker.com/network/network-tutorial-macvlan/">https://docs.docker.com/network/network-tutorial-macvlan/</a></p><p><a href="http://yangjunsss.github.io/2018-07-29/Docker-%E7%BD%91%E7%BB%9C-Host-Bridge-Macvlan-%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%E5%92%8C%E9%AA%8C%E8%AF%81/">http://yangjunsss.github.io/2018-07-29/Docker-%E7%BD%91%E7%BB%9C-Host-Bridge-Macvlan-%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%E5%92%8C%E9%AA%8C%E8%AF%81/</a></p><p><a href="https://cloud.tencent.com/developer/article/1432601">https://cloud.tencent.com/developer/article/1432601</a></p><p><a href="https://cloud.tencent.com/developer/news/563351">https://cloud.tencent.com/developer/news/563351</a></p> Sat, 10 Jul 2021 04:58:22 GMT ttyS3 podmanipmacvlannetwork https://ttys3.dev/blog/add-an-app-to-run-automatically-at-startup-in-windows-10 Windows 10 添加程序到自启动的简单方法 https://ttys3.dev/blog/add-an-app-to-run-automatically-at-startup-in-windows-10 <p>简单方法当然指的是点两下鼠标完事的。</p><p>方法当然是自来 <a href="https://support.microsoft.com/en-us/windows/add-an-app-to-run-automatically-at-startup-in-windows-10-150da165-dcd9-7230-517b-cf3c295d89dd">官方文档</a></p><ol><li>Select the <strong>Start</strong>  button and scroll to find the app you want to run at startup.</li><li>Right-click the app, select <strong>More</strong>, and then select <strong>Open file location</strong>. This opens the location where the shortcut to the app is saved. If there isn&#x27;t an option for <strong>Open file location</strong>, it means the app can&#x27;t run at startup.</li><li>With the file location open, press the <strong>Windows logo key</strong>  + <strong>R</strong>, type <strong>shell:startup</strong>, then select <strong>OK</strong>. This opens the <strong>Startup</strong> folder.</li><li>Copy and paste the shortcut to the app from the file location to the <strong>Startup</strong> folder.</li></ol><p>中文版:</p><ol><li>选择“<strong>开始</strong>”按钮 ,然后滚动查找你希望在启动时运行的应用。</li><li>右键单击该应用,选择**“更多”<strong>,然后选择</strong>“打开文件位置”**。此操作会打开保存应用快捷方式的位置。如果没有“<strong>打开文件位置</strong>”选项,这意味着该应用无法在启动时运行。</li><li>文件位置打开后,按 <strong>Windows 徽标键</strong>  + <strong>R</strong>,键入“<strong>shell:startup</strong>”,然后选择“<strong>确定</strong>”。这将打开“<strong>启动</strong>”文件夹。</li><li>将该应用的快捷方式从文件位置复制并粘贴到**“启动”**文件夹中。</li></ol> Tue, 29 Jun 2021 17:07:05 GMT ttyS3 windowsstartupwin10 https://ttys3.dev/blog/windows-webview2-and-rust Windows WebView2 and Rust https://ttys3.dev/blog/windows-webview2-and-rust <p>在 WebView2 出来之前,如果想要基于 webivew 技术开发桌面应用,在 Mac OSX 上面可以用 <a href="https://webkit.org/">webkit</a>, 在 Linux 上面可以用 GTK 版的 <a href="https://webkitgtk.org/">webkitgtk</a>, 但是在 Windows 上面只能用 <a href="https://en.wikipedia.org/wiki/Trident_(software)">MSHTML</a>, 这个 MSHTML 使用起来各种不兼容。</p><p>现在,随着 m$ 的 edge 浏览器拥抱 Chromium 内核,<code>WebView2</code> 的出现,使得情况得到很大的改善。</p><p>这里的 <code>WebView2</code> 是专门指的 微软的 <a href="https://developer.microsoft.com/en-us/microsoft-edge/webview2/">WebView2</a></p><p>微软貌似比较喜欢 Rust, 还专门给 Rust 做了 windows 绑定:</p><p><a href="https://docs.microsoft.com/en-us/windows/dev-environment/rust/rust-for-windows">https://docs.microsoft.com/en-us/windows/dev-environment/rust/rust-for-windows</a></p><p><a href="https://crates.io/crates/windows">https://crates.io/crates/windows</a></p><p><a href="https://github.com/microsoft/windows-rs/">https://github.com/microsoft/windows-rs/</a></p><p>官方 crate 里面是有一个叫 <code>WebView</code> 的<a href="https://microsoft.github.io/windows-docs-rs/doc/bindings/Windows/UI/Xaml/Controls/struct.WebView.html">控件</a>的,不过好像没有看到 example</p><p>当前 WebView2 支持的系统包括:</p><ul><li>Windows 10</li><li>Windows 8.1</li><li>Windows 7</li><li>Windows Server 2019</li><li>Windows Server 2016</li><li>WindowsServer 2012</li><li>Windows Server 2012 R2</li><li>WindowsServer 2008 R2</li></ul><p>连 Windows 7 都支持了,所以,其实系统方面不用担心了。这年头谁还用 XP ?</p><h2 id="distribution-of-apps-using-webview2"><a href="#distribution-of-apps-using-webview2" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Distribution of apps using WebView2</h2><p>基于 WebView2 的应用如何分发?</p><p>因为目前 WebView2 的运行时是需要单独安装的。</p><h2 id="什么是-webview2-运行时"><a href="#什么是-webview2-运行时" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>什么是 WebView2 运行时</h2><blockquote><p>WebView2 运行时是一个可再发行运行时,并用作 WebView2 应用的支持 Web 平台。 此概念类似于 Visual C++/.NET 应用的 .NET 运行时。 运行时包含经过修改Microsoft Edge (Chromium) 已针对应用进行优化和测试的二进制文件。 运行时在安装时不会显示为用户可见的浏览器。</p><p>在生产环境中,在应用启动之前,必须确保运行时存在于用户设备上。 Microsoft Edge Stable 渠道不可用于 WebView2。 该决定可防止应用在生产中依赖浏览器。</p></blockquote><p>为什么 WebView2 运行时 需要独立安装,微软也给出了详细的解释:</p><blockquote><p>Microsoft Edge (Chromium) 不一定存在于所有用户设备上。 例如,与 Windows Update 断开连接或不由 Microsoft 直接管理的设备 (大部分 Enterprise 和 EDU 市场) 可能没有浏览器。 允许分发 WebView2 运行时可以避免依赖浏览器作为应用的先决条件。 浏览器和应用具有不同的用例,因此依赖浏览器可能会对应用产生意外的负面影响。 例如,IT 管理员可以对浏览器进行版本控制,以确保内部网站兼容性。 WebView2 运行时允许应用在主动管理浏览器更新时保持常青。 与浏览器相反,运行时针对应用方案进行开发和测试,并且在某些情况下可能包括浏览器中尚未提供的 Bug 修复。</p></blockquote><p>这也就是为什么 WebView2 的运行时是需要单独安装。微软特意为之的, 将 WebView2 运行时与 Microsoft Edge 浏览器分开,还有另一个好处是,并不是所有人都愿意使用 Edge 浏览器,你总不能期望别人为了使用一个基于 WebView2 的 app 要安装整个 Edge 浏览器 吧?所以,老灯也觉得 ,WebView2 运行时独立安装, 虽然对于软件分布来说会增加一些困难,但是其实是优点多于缺点的。</p><h2 id="分发模式"><a href="#分发模式" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>分发模式</h2><ul><li>常青分发模式</li><li>固定版本分发模式</li></ul><p>这两种方式各有好处和坏处吧,主要看具体需求。</p><h3 id="常青分发模式"><a href="#常青分发模式" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>常青分发模式</h3><p>常青分发需要你的应用保持和较新版本的运行时兼容。</p><p>其中,常青分发模式部署的又分为:</p><ul><li>联机部署</li><li>脱机部署</li></ul><p>注: 无论哪种部署,必要的操作包含:在应用安装程序或更新程序中包括运行时安装程序(Evergreen Bootstrapper 或 Evergreen Standalone Installer)</p><p>所谓“联机部署” 就是 app 在运行的时候,检测运行时是否已经安装,如果没有安装,则运行一个 2M 左右的运行时下载器(Evergreen Bootstrapper)</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 静默安装 Evergreen Bootstrapper</span> </span><span class="code-line">MicrosoftEdgeWebview2Setup.exe /silent /install </span></code></pre></div><p>该方式具有以下优点:</p><ul><li>仅在需要或不需要打包安装程序时安装运行时。</li><li>引导程序自动检测设备体系结构并安装匹配的运行时。</li><li>以静默方式安装运行时。</li><li>还可以选择将引导程序打包到你的应用中,而不是以编程方式按需下载它。</li></ul><p>所谓“脱机部署” 就是 app 在运行的时候,检测运行时是否已经安装,如果没有安装,则执行独立安装程序</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">MicrosoftEdgeWebView2RuntimeInstaller<span class="token punctuation">{</span>X64/X86/ARM64<span class="token punctuation">}</span>.exe /silent /install </span></code></pre></div><h4 id="部署-evergreen-webview2-运行时"><a href="#部署-evergreen-webview2-运行时" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>部署 Evergreen WebView2 运行时</h4><blockquote><p>设备上的所有 Evergreen 应用只需安装一次 Evergreen WebView2 运行时。 WebView2 运行时下载页上提供了 许多工具。 以下工具可帮助你部署常青运行时。</p></blockquote><ul><li>WebView2 运行时引导程序是一个小的 (大约 2 MB) 安装程序。 WebView2 运行时引导程序从与用户设备体系结构匹配的 Microsoft 服务器下载并安装 Evergreen Runtime。</li><li>使用链接以编程方式下载引导程序。</li><li>WebView2 运行时独立安装程序是在脱机环境中安装 Evergreen WebView2 运行时的完整安装程序。 目前,引导程序和独立安装程序仅支持每台计算机安装,这需要提升。 如果安装程序在未提升权限的情况下运行,系统将提示用户提升权限。</li></ul><h3 id="固定版本分发模式"><a href="#固定版本分发模式" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>固定版本分发模式</h3><p>固定版本分发模式以前称为自带发布。这种分发方式,其实就是你下载好了一个特定版本的运行时,解压出来,直接打包集成到你的应用程序里面。</p><blockquote><p>对于具有严格兼容性要求的限制环境,请考虑使用固定版本分发模式。 使用固定版本分发模式选择并打包特定版本的 WebView2 运行时。 你可以为你的应用指定运行时更新的时间。 固定版本分发模式不会接收任何自动更新。 计划更新你的应用和运行时。</p></blockquote><p>若要使用固定版本模式,请完成以下操作</p><ol><li><p><a href="https://developer.microsoft.com/microsoft-edge/webview2" title="WebView2 安装程序|Microsoft 开发人员">下载</a> 固定版本程序包。</p></li><li><p>使用命令行或 WinRAR 等 <code>expand {path to the package} -F:* {path to the destination folder}</code> 工具解压缩包。 避免通过文件资源管理器解压缩,因为它可能无法生成正确的文件夹结构。</p></li><li><p>在项目中包括解压缩的固定版本二进制文件。</p></li><li><p>指示创建 WebView2 环境时固定版本二进制文件的路径。</p><ul><li><p>对于 Win32 C/C++,可以使用 <a href="https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions" title="CreateCoreWebView2EnvironmentWithOptions - 全局|Microsoft Docs">CreateCoreWebView2EnvironmentWithOptions</a> 函数创建环境。 使用 <code>browserExecutableFolder</code> 参数指示包含 的文件夹的路径 <code>msedgewebview2.exe</code> 。</p></li><li><p>对于 .NET,您可以执行以下任一选项来指定环境。</p><p> 备注</p><p>必须指定环境,WebView2 <code>Source</code> 属性才能生效。</p><ul><li>在 <code>CreationProperties</code> <a href="https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.web.webview2.wpf.webview2.creationproperties" title="CreationProperties - Microsoft.Web.WebView2.Wpf.WebView2 类|Microsoft Docs"></a>/ WebView2 (设置 ) WPF<a href="https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.web.webview2.winforms.webview2" title="Microsoft.Web.WebView2.WinForms.WebView2 类|Microsoft Docs">WinForms</a>) 属性。 使用 <code>BrowserExecutableFolder</code> <code>CoreWebView2CreationProperties</code> (<a href="https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.web.webview2.wpf.corewebview2creationproperties" title="CoreWebView2CreationProperties - Microsoft.Web.WebView2.Wpf.CoreWebView2CreationProperties 类|Microsoft Docs">WPF</a> / <a href="https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.web.webview2.winforms" title="Microsoft.Web.WebView2.WinForms 类|Microsoft Docs">WinForms</a>) 类中的成员指示固定版本二进制文件的路径。</li><li>使用 <code>EnsureCoreWebView2Async</code> (<a href="https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.web.webview2.wpf.webview2.ensurecorewebview2async" title="EnsureCoreWebView2Async -Microsoft.Web.WebView2.Wpf.WebView2 类|Microsoft Docs">WPF</a> / <a href="https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.web.webview2.winforms.webview2.ensurecorewebview2async" title="EnsureCoreWebView2Async - Microsoft.Web.WebView2.WinForms.WebView2 类|Microsoft Docs">WinForms</a>) 指定环境。 使用 <code>browserExecutableFolder</code> <a href="https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.web.webview2.core.corewebview2environment.createasync" title="CreateAsync - Microsoft.Web.WebView2.Core.CoreWebView2Environment 类|Microsoft Docs">CoreWebView2Environment.CreateAsync</a> 中的 参数指示固定版本二进制文件的路径。</li></ul></li></ul></li><li><p>将固定版本二进制文件打包并随你的应用一起提供。 根据情况更新二进制文件。</p></li></ol><p>看了下, ms 的 rust crate 里面并没有包含 <code>CreateCoreWebView2EnvironmentWithOptions</code> 相关的东西,github 上面有一个Rust 绑定 <code>https://github.com/sopium/webview2</code></p><p>有提供这个方法:<a href="https://docs.rs/webview2/0.1.0/webview2/struct.EnvironmentBuilder.html">https://docs.rs/webview2/0.1.0/webview2/struct.EnvironmentBuilder.html</a></p><p>A builder for calling the <code>CreateCoreWebView2EnvironmentWithOptions</code> function.</p><p>Use <code>Environment::builder()</code> to create one.</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p>使用 WebView2 分发应用: <a href="https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution">https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution</a></p><p>运行时下载: <a href="https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/">https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/</a></p><p>WebView2 介绍: <a href="https://developer.microsoft.com/en-us/microsoft-edge/webview2/">https://developer.microsoft.com/en-us/microsoft-edge/webview2/</a></p><p>管理用户数据文件夹 <a href="https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/concepts/user-data-folder">https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/concepts/user-data-folder</a></p><p>开发安全 WebView2 应用的最佳方案 <a href="https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/concepts/security">https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/concepts/security</a></p><p>了解 WebView2 SDK 版本 <a href="https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/concepts/versioning">https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/concepts/versioning</a></p><p>如何调试 WebView2 应用 <a href="https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/how-to/debug?tabs=devtools">https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/how-to/debug?tabs=devtools</a></p> Sun, 27 Jun 2021 16:28:00 GMT ttyS3 WebView2webviewmicrosoftedgeRustbindingsruntime https://ttys3.dev/blog/gtk-rs-now-provides-bindings-for-gtk4-libraries gtk-rs 现已支持 GTK4 绑定 https://ttys3.dev/blog/gtk-rs-now-provides-bindings-for-gtk4-libraries <p>6 月 22 日 gtk-rs <a href="https://gtk-rs.org/blog/2021/06/22/new-release.html">官方博客</a>就发文了</p><p>距离上次发布已经过去很长时间了,正如您所猜测的,在这段时间内发生了很多事情。让我们从最重要的开始:</p><p>gtk-rs 现在为 GTK4 库提供绑定!</p><p>它们都可以在 gtk4-rs 仓库中找到。</p><p>甚至还写了一本介绍书来教用户如何使用 gtk4-rs。你可以在<a href="https://gtk-rs.org/gtk4-rs/stable/latest/book/">这里</a>阅读它。接下来几天将发布有关 GTK4 的更详细的博客文章。</p><h2 id="新网站和新logo"><a href="#新网站和新logo" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>新网站和新logo</h2><p>我们利用这个机会彻底重新设计了网站并制作了一个logo。既然你已经来了,不要犹豫,去看看吧!</p><h2 id="gnome-圈子"><a href="#gnome-圈子" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>GNOME 圈子</h2><p>gtk-rs 现在是 “GNOME 圈子“ 的一部分!除了一些其他好处之外,它还允许我们的贡献者加入 GNOME 基金会。查看网站了解更多详情。</p><h2 id="git-仓库更改"><a href="#git-仓库更改" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>git 仓库更改</h2><p>此版本还对 gtk-rs 仓库结构进行了更改。我们现在有三个主要仓库:</p><p><a href="https://github.com/gtk-rs/gtk-rs-core">gtk-rs-core</a>:它包含被认为是“核心”的 crate,因为它们同时被 GTK3 和 GTK4 使用,但也被其他项目如 gstreamer-rs 使用:</p><ul><li>cairo</li><li>gdk-pixbuf</li><li>gio</li><li>glib</li><li>glib-macros</li><li>graphene</li><li>pango</li><li>pangocairo</li></ul><p><a href="https://github.com/gtk-rs/gtk3-rs">gtk3-rs</a>:包含属于 GTK3 生态系统的 crate:</p><ul><li>atk</li><li>gdk</li><li>gdkx11</li><li>gtk3-macros</li></ul><p><a href="https://github.com/gtk-rs/gtk4-rs">gtk4-rs</a>:包含属于 GTK4 生态系统一部分的 crate:</p><ul><li>gdk4</li><li>gdk4-wayland</li><li>gdk4-x11</li><li>gsk4</li><li>gtk4</li><li>gtk4-macros</li></ul><p>关于这一点的另一个重点是:一个存储库中的所有 crate 现在共享相同的版本号。之前它有点乱,所以我们决定简化它。所以这里是每个存储库的版本号:</p><ul><li><a href="https://github.com/gtk-rs/gtk-rs-core">gtk-rs-core</a>: 0.14</li><li><a href="https://github.com/gtk-rs/gtk3-rs">gtk3-rs</a>: 0.14</li><li><a href="https://github.com/gtk-rs/gtk4-rs">gtk4-rs</a>: 0.1</li></ul><h2 id="文档改进"><a href="#文档改进" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>文档改进</h2><p>gtk-rs crates 使用 C 文档,但是我们改进了它的渲染以使其对 Rust 开发人员更有用:</p><ul><li>现在可以正确生成条目的链接。</li><li>如果代码示例不是用 Rust 编写的,我们现在添加警告以避免混淆。</li><li>我们添加了文档别名,因此您现在可以直接搜索信号名称甚至 C 函数名称。</li><li>现在还记录了全局函数、构建器模式、常量和静态。</li><li>不再呈现 C 特定的参数,因此不在 Rust 绑定中使用。</li></ul><h2 id="依赖项被重新导出"><a href="#依赖项被重新导出" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>依赖项被重新导出</h2><p>我们举个例子,而不是冗长的解释。您有一个 GTK 应用程序,并且还使用 Cairo 和 GDK。在此版本之前,您需要将所有 3 个依赖项添加到 Cargo.toml 文件中以便能够使用它们。现在,您只需要导入 GTK 即可:</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">gtk<span class="token punctuation">::</span></span><span class="token punctuation">{</span>cairo<span class="token punctuation">,</span> gdk<span class="token punctuation">}</span><span class="token punctuation">;</span> </span></code></pre></div><p>就是这样!它将使您对依赖项的管理更加简单。需要注意的是,它们也在前奏中,因此导入它将使您可以访问它们:</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">gtk<span class="token punctuation">::</span>prelude<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// ...</span> </span><span class="code-line"><span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token namespace">cairo<span class="token punctuation">::</span></span><span class="token function">something</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">let</span> y <span class="token operator">=</span> <span class="token namespace">gdk<span class="token punctuation">::</span></span><span class="token function">something</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>关于重新导出的最后一条说明: <code>-sys</code> crates 也以 <code>ffi</code> 的名称重新导出:</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">gtk<span class="token punctuation">::</span></span>ffi<span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// You now have access to all raw C-functions of GTK.</span> </span><span class="code-line"><span class="token comment">// 您现在可以访问 GTK 的所有原始 C 函数。</span> </span></code></pre></div><h2 id="重构-value-trait"><a href="#重构-value-trait" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>重构 Value trait</h2><p>主要的变化是对于不可为空的类型 <code>Value::get()</code> 永远不会返回 <code>None</code>,取代了之前令人困惑的 <code>Value::get_some()</code>。</p><p>此外,现在可以直接将 <code>Value::get()</code> 设为可空类型,而无需 <code>Option</code> 包装。如果该值实际上是 <code>None</code> 这将返回一个 <code>Err</code>。在值为 <code>None</code> 的情况下,这避免了一层展开。</p><p>还有一个新的通用的 <code>ValueType</code> trait,它由可在 <code>Value</code> 中使用的所有类型实现,并允许 存储/检索 此值的类型 into/from 一个<code>Value</code> (这里有点绕,觉得没翻译正确,原谅老灯吧 :( )。 我贴出原文:There is also a new generic <code>ValueType</code> trait that is implemented by all types that can be used inside a <code>Value</code> and that allows storing/retrieving types of this value into/from a <code>Value</code>.</p><h2 id="添加了-gtk-复合模板支持"><a href="#添加了-gtk-复合模板支持" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>添加了 GTK 复合模板支持</h2><p>要从 UI 文件构建小部件,您可以使用 gtk::Builder 或复合模板。对于前者,您必须保留一个 gtk::Builder 实例。使用复合模板时,您可以让您的自定义小部件(gtk::Widget 的子类)在内部使用该模板,区别在于能够通过定义在不同的 UI 文件中使用您的 CustomWidget:</p><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>object</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>CustomWidget<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>some-property<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>some-value<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>object</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>您现在可以让您的 <code>CustomWidget</code> 使用 <code>#[CompositeTemplate]</code> 派生宏。这项工作最初是为 GTK4 Rust 绑定完成的,但也向后移植到 GTK3。有关示例,请参见<a href="https://gtk-rs.org/gtk4-rs/stable/0.1/docs/gtk4_macros/derive.CompositeTemplate.html">此处</a>或<a href="https://github.com/gtk-rs/gtk4-rs/tree/0.1/examples/composite_template">此处</a>。</p><p>复合模板还允许您使用在 <code>CustomWidget</code> 上定义的方法作为直接来自 UI 文件的信号的回调,即使宏目前不支持 GTK3/GTK4 绑定......但别担心,<a href="https://github.com/gtk-rs/gtk3-rs/issues/128">我们正在努力解决</a>!</p><h2 id="新的和改进的宏"><a href="#新的和改进的宏" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>新的和改进的宏</h2><p>除了 <code>glib::object_subclass</code> 属性宏(请参阅有关子类化改进的段落的链接)之外,glib 现在还提供了一些其他宏,以使应用程序开发更容易并减少样板:</p><p><a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib/macro.clone.html">glib::clone!</a>:这个宏允许自动克隆或创建弱引用加上闭包的升级,并大大简化了信号处理程序闭包的创建。该文档包含几个示例。虽然这个宏存在于</p><p>最后一个版本,它被完全重写并变得更强大,并获得了一个伴随的派生宏 glib::Downgrade,它使用所需的机制扩展自定义类型,用于克隆上下文中的弱引用!宏。 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/derive.GBoxed.html"><code>glib::GBoxed</code></a> 和 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/derive.GSharedBoxed.html"><code>glib::GSharedBoxed</code></a>:这些派生宏允许在 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib/value/struct.Value.html"><code>glib::Value</code></a>s 中使用自定义 Rust 类型,这是 GObject 属性和信号参数/返回值或 GTK 树视图的内容所必需的。第一个宏总是在必要时克隆底层值,而第二个宏使用引用计数而不是正常克隆。 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/attr.gflags.html"><code>glib::gflags!</code></a>和 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/derive.GEnum.html"><code>glib::GEnum</code></a>:这些宏允许在 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib/value/struct.Value.html"><code>glib::Value</code></a>s 中使用 Rust 枚举和位标志。有关示例,请参阅子<a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib/subclass/index.html#example-for-registering-a-glibobject-subclass">subclassing docs</a>。 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/derive.GErrorDomain.html"><code>glib::GErrorDomain</code></a>:这个派生宏允许使用合适的 Rust 枚举作为 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib/error/struct.Error.html"><code>glib::Error</code></a>s 的错误域。</p><p>有关 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/derive.GBoxed.html"><code>glib::GBoxed</code></a>、<a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/attr.gflags.html"><code>glib::gflags</code></a> 和 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/derive.GEnum.html"><code>glib::GEnum</code></a> 宏的更多示例,另请参阅子<a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib/subclass/index.html#example-for-registering-a-glibobject-subclass">subclassing</a>文档。</p><h2 id="子类化subclassing的改进"><a href="#子类化subclassing的改进" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>子类化(subclassing)的改进</h2><p>由于引入了 <a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib_macros/attr.object_subclass.html">glib::object_subclass</a> <code>derive</code> 派生宏,因此实现 GObject 更加简单。此外,注册属性和信号现在需要更少的样板。请参阅此<a href="https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/glib/subclass/index.html#example-for-registering-a-glibobject-subclass">页面</a>以获取完整示例,但最小示例现在如下所示:</p><div class="relative"><pre><code class="language-rust code-highlight"><span class="code-line"><span class="token keyword">mod</span> <span class="token namespace module-declaration">imp</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token attr-name attribute">#[derive(Default)]</span> </span><span class="code-line"> <span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token class-name type-definition">MyObject</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token attr-name attribute">#[glib::object_subclass]</span> </span><span class="code-line"> <span class="token keyword">impl</span> <span class="token class-name">ObjectSubclass</span> <span class="token keyword">for</span> <span class="token class-name">MyObject</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">const</span> <span class="token constant">NAME</span><span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">&#x27;static</span> <span class="token keyword">str</span> <span class="token operator">=</span> <span class="token string">&quot;MyObject&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">type</span> <span class="token class-name type-definition">Type</span> <span class="token operator">=</span> <span class="token keyword">super</span><span class="token punctuation">::</span><span class="token class-name">MyObject</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">type</span> <span class="token class-name type-definition">ParentType</span> <span class="token operator">=</span> <span class="token namespace">glib<span class="token punctuation">::</span></span><span class="token class-name">Object</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">impl</span> <span class="token class-name">ObjectImpl</span> <span class="token keyword">for</span> <span class="token class-name">MyObject</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token namespace">glib<span class="token punctuation">::</span></span><span class="token macro property">wrapper!</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token class-name type-definition">MyObject</span><span class="token punctuation">(</span><span class="token class-name">ObjectSubclass</span><span class="token operator">&lt;</span><span class="token namespace">imp<span class="token punctuation">::</span></span><span class="token class-name">MyObject</span><span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">impl</span> <span class="token class-name">MyObject</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function function-definition">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">Self</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token namespace">glib<span class="token punctuation">::</span></span><span class="token class-name">Object</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h2 id="更好的cairo错误处理"><a href="#更好的cairo错误处理" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>更好的cairo错误处理</h2><p>使用 cairo 现在更符合人体工程学:fill() 或stroke() 等函数返回结果,而不需要手动检查Context::status()。此外,所有在 cairo 状态上对 expect() 的内部调用都被删除了,使调用者能够处理错误情况,而不是引起 panic.</p><h2 id="gir教程"><a href="#gir教程" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Gir教程</h2><p><strong>gtk-rs</strong> crates 大多能自动生成,这要归功于 <strong><a href="https://github.com/gtk-rs/gir">gir</a></strong> 项目。如果您还想生成自己的基于 GObject 的 crate 绑定,也可以使用它!为了帮助您,我们开始了一本教程书,可在<a href="https://gtk-rs.org/gir/book/">此处</a>获取。</p><h2 id="命名改进"><a href="#命名改进" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>命名改进</h2><p>我们重命名了许多函数/方法,以使它们更符合 Rust 标准。具体来说,getter 函数从 <strong>get_something</strong>() 重命名为 <strong>something</strong>() 或 <strong>is_something</strong>(),而 setter 保持为 <strong>set_something</strong>()。此外,GObject 属性 getter/setter 失去了名称中的属性名称(即 <strong>set_property_something</strong>() 被 <strong>set_something</strong>() 取代)。</p><p>在此注意事项:</p><h3 id="应用程序开发人员注意事项"><a href="#应用程序开发人员注意事项" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>应用程序开发人员注意事项</h3><p>应用程序开发人员应该使用 <a href="https://crates.io/crates/fix-getters-calls">fix-getters-calls</a> 来简化应用程序的迁移。如果您还希望 get 函数定义符合此版本中应用的 API 标准,请使用 <a href="https://crates.io/crates/fix-getters-def">fix-getters-def</a>。</p><h2 id="最低支持版本"><a href="#最低支持版本" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>最低支持版本</h2><p>gtk-rs 最低支持的 <strong>Rust</strong> 版本现在是 <strong>1.51</strong></p><ul><li>ATK: 2.18</li><li>Cairo: 1.14</li><li>GDK3: 3.18</li><li>GDK4: 4.0</li><li>GDK4-Wayland: 4.0</li><li>GDKX11: 3.18</li><li>GDK4-X11: 4.0</li><li>GDK-Pixbuf: 2.32</li><li>Gio: 2.48</li><li>GLib: 2.48</li><li>Graphene: 1.10</li><li>GSK4: 4.0</li><li>GTK3: 3.20</li><li>GTK4: 4.0</li><li>Pango: 1.38</li><li>PangoCairo: 1.38</li></ul><h2 id="迁移到-rust-2018-版"><a href="#迁移到-rust-2018-版" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>迁移到 Rust 2018 版</h2><p>gtk-rs crates 全部迁移到 Rust 2018 版本。正好因为 2021 年版越来越近了!</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://gtk-rs.org/gtk4-rs/stable/latest/book/">https://gtk-rs.org/gtk4-rs/stable/latest/book/</a></p><p><a href="https://gtk-rs.org/blog/2021/06/22/new-release.html">https://gtk-rs.org/blog/2021/06/22/new-release.html</a></p> Sat, 26 Jun 2021 05:39:45 GMT ttyS3 gtk-rsrustgtkgtk4bindings https://ttys3.dev/blog/port-extensions-to-gnome-shell-40 Port Extensions to GNOME Shell 40 https://ttys3.dev/blog/port-extensions-to-gnome-shell-40 <p>2021年4月份新发布的 <a href="https://fedoramagazine.org/whats-new-fedora-34-workstation/">Fedora Workstation 34</a> 率先引入 GNOME 40.</p><p>Arch 也紧随其后发布了 GNOME 40 相关 package .</p><p>Ubuntu 21.04 之前传言是会有 GNOME 40, 但是最后临阵退缩了。不过 Ubuntu 相关的开发人员弄了一个 ppa 可以安装测试 (<a href="https://www.debugpoint.com/2021/04/gnome-40-ubuntu-21-04/%EF%BC%89%E3%80%82">https://www.debugpoint.com/2021/04/gnome-40-ubuntu-21-04/)。</a></p><p>老灯使用 <a href="https://forty.gnome.org/">GNOME 40</a> 已经有一段时间了。大部分必备的 extension 都已经升级支持 GNOME 40 了。如果有少量几个必须的不兼容 40 ,但是原作者又没更新怎么办? 只能自己动手了。</p><h2 id="官方-port-guide"><a href="#官方-port-guide" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>官方 port guide</h2><p>GNOME shell 扩展是基于 js 的, 解析执行靠 <code>gjs</code> , 事实上 <code>gjs</code> 不只支持写扩展,它完全支持写任何 gtk 应用。流行的电子书阅读器 <a href="https://github.com/johnfactotum/foliate">Foliate</a> 就是 基于 js 写的</p><h3 id="metadatajson"><a href="#metadatajson" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>metadata.json</h3><p>如果代码层面没有不工作的地方,最简单的 port 就是一句话,修改 <code>metadata.json</code> <code>shell-version</code> 增加 <code>40</code></p><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property string-property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Extension Name&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property string-property">&quot;description&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Extension Description&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property string-property">&quot;shell-version&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">&quot;3.36&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;40&quot;</span><span class="token punctuation">]</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property string-property">&quot;url&quot;</span><span class="token operator">:</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property string-property">&quot;uuid&quot;</span><span class="token operator">:</span> <span class="token string">&quot;example@example&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property string-property">&quot;version&quot;</span><span class="token operator">:</span> <span class="token number">1</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h3 id="检查-gnome-shell-和-gtk-版本"><a href="#检查-gnome-shell-和-gtk-版本" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>检查 GNOME Shell 和 GTK 版本</h3><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token keyword">const</span> <span class="token maybe-class-name">Config</span> <span class="token operator">=</span> imports<span class="token punctuation">.</span><span class="token property-access">misc</span><span class="token punctuation">.</span><span class="token property-access">config</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">const</span> <span class="token punctuation">[</span>major<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token maybe-class-name">Config</span><span class="token punctuation">.</span><span class="token constant">PACKAGE_VERSION</span><span class="token punctuation">.</span><span class="token property-access function method">split</span><span class="token punctuation">(</span><span class="token string">&#x27;.&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">const</span> shellVersion <span class="token operator">=</span> <span class="token class-name known-class-name">Number</span><span class="token punctuation">.</span><span class="token property-access function method">parseInt</span><span class="token punctuation">(</span>major<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>shellVersion <span class="token operator">&lt;</span> <span class="token number">40</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&#x27;Shell 3.38 or lower&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword control-flow">else</span> </span><span class="code-line"> <span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&#x27;Shell 40 or higher&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token keyword">const</span> <span class="token punctuation">{</span><span class="token maybe-class-name">Gtk</span><span class="token punctuation">}</span> <span class="token operator">=</span> imports<span class="token punctuation">.</span><span class="token property-access">gi</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">const</span> gtkVersion <span class="token operator">=</span> <span class="token maybe-class-name">Gtk</span><span class="token punctuation">.</span><span class="token property-access function method">get_major_version</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">GTK version is </span><span class="token interpolation"><span class="token punctuation interpolation-punctuation">${</span>gtkVersion<span class="token punctuation interpolation-punctuation">}</span></span><span class="token string template-punctuation">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><h3 id="仅在存在时导入命名空间"><a href="#仅在存在时导入命名空间" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>仅在存在时导入命名空间</h3><p>在GNOME Shell 40 上有一些新命名空间,同时,有一些旧的命名空间已经被删除了。 如果想要导入某个可能存在的命名空间时,则可以使用 try and catch block 语法:</p><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token keyword control-flow">try</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">const</span> <span class="token maybe-class-name">SearchController</span> <span class="token operator">=</span> imports<span class="token punctuation">.</span><span class="token property-access">ui</span><span class="token punctuation">.</span><span class="token property-access">searchController</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword control-flow">catch</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;SearchController doesn&#x27;t exist&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>你还可以检查GNOME shell版本,然后导入对应版本的命名空间:</p><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token keyword">const</span> <span class="token maybe-class-name">Config</span> <span class="token operator">=</span> imports<span class="token punctuation">.</span><span class="token property-access">misc</span><span class="token punctuation">.</span><span class="token property-access">config</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">const</span> <span class="token punctuation">[</span>major<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token maybe-class-name">Config</span><span class="token punctuation">.</span><span class="token constant">PACKAGE_VERSION</span><span class="token punctuation">.</span><span class="token property-access function method">split</span><span class="token punctuation">(</span><span class="token string">&#x27;.&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">const</span> shellVersion <span class="token operator">=</span> <span class="token class-name known-class-name">Number</span><span class="token punctuation">.</span><span class="token property-access function method">parseInt</span><span class="token punctuation">(</span>major<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">const</span> <span class="token maybe-class-name">SearchController</span> <span class="token operator">=</span> <span class="token punctuation">(</span>shellVersion <span class="token operator">&gt;=</span> <span class="token number">40</span><span class="token punctuation">)</span> <span class="token operator">?</span> imports<span class="token punctuation">.</span><span class="token property-access">ui</span><span class="token punctuation">.</span><span class="token property-access">searchController</span> <span class="token operator">:</span> <span class="token keyword nil null">null</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token maybe-class-name">SearchController</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;SearchController doesn&#x27;t exist&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h3 id="顶部面板"><a href="#顶部面板" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>顶部面板</h3><p>GNOME 40 从顶部面板中删除了弹出菜单箭头。 虽然不推荐,但如果你想添加一个箭头图标,代码仍然存在</p><p><code>ui.popupMenu.arrowIcon()</code> (<a href="https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/40e22eb524556e63efa4285c1a9d8f872a507499/js/ui/popupMenu.js#L34%EF%BC%89">https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/40e22eb524556e63efa4285c1a9d8f872a507499/js/ui/popupMenu.js#L34)</a></p><h3 id="overview-概览-elements"><a href="#overview-概览-elements" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Overview (概览) Elements</h3><p>GNOME Shell 40 中的大多数更改都与概览有关。 如果您的扩展程序正在使用概览元素执行某些操作,您将需要适应这些更改。</p><p>这里有点多,直接贴官方链接吧: <a href="https://gjs.guide/extensions/upgrading/gnome-shell-40.html#overview-elements">https://gjs.guide/extensions/upgrading/gnome-shell-40.html#overview-elements</a></p><h3 id="prefs-偏好设置"><a href="#prefs-偏好设置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Prefs 偏好设置</h3><p>这部分改动应该是最大的。</p><p>GNOME Shell 40 现在使用 GTK4 作为扩展首选项。 这意味着您需要将 prefs.js UI 升级到 GTK4。</p><p>强烈建议使用模板文件 (.ui) 创建 GTK UI。 这种结构将后端和前端代码解耦,使您的工作更易于升级和更易于维护。</p><p>如果您当前没有使用模板文件,将您当前的 UI 移动到模板文件,然后将其移植到 GTK4 会更容易。 如果您不熟悉模板文件,您可以使用 Glade 创建您的模板文件(Glade 不支持 GTK4,但您可以使用 Glade 创建您的文件,然后将它们移植到 GTK4。有关说明,请参阅转换和验证模板文件)。</p><p>转换 gtk3 模板到 gtk4: <a href="https://gjs.guide/extensions/upgrading/gnome-shell-40.html#convert-and-validate-template-files">https://gjs.guide/extensions/upgrading/gnome-shell-40.html#convert-and-validate-template-files</a></p><p>To check whether the .ui template file is compatible with GTK4 you can do this:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">gtk4-builder-tool validate path_to_ui_file </span></code></pre></div><p>You can also convert your file to GTK4:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">gtk4-builder-tool simplify <span class="token parameter variable">--3to4</span> path_to_ui_file </span></code></pre></div><p>If you want to replace the file with simplified version:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">gtk4-builder-tool simplify <span class="token parameter variable">--3to4</span> <span class="token parameter variable">--replace</span> path_to_ui_file </span></code></pre></div><p>虽然构建器工具simple 可以帮助您将 gtk3 转换为 gtk4,但它无法转换所有内容。 您需要手动更改某些部分。</p><h4 id="show_all-and-destroy"><a href="#show_all-and-destroy" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>show_all and destroy</h4><p>在 GTK4 中,默认情况下所有小部件都是可见的(顶层窗口、弹出窗口和对话框除外)。</p><p>不再需要在您的小部件中使用 show_all() 和 destroy 信号:</p><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token keyword">function</span> <span class="token function">buildPrefsWidget</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> widget <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyPrefsWidget</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// widget.show_all();</span> </span><span class="code-line"> <span class="token comment">// widget.connect(&#x27;destroy&#x27;, Gtk.main_quit);</span> </span><span class="code-line"> <span class="token keyword control-flow">return</span> widget<span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h4 id="provide-css-file-for-prefs"><a href="#provide-css-file-for-prefs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Provide css file for prefs</h4><p>GTK4 上没有任何样式属性。 您应该改用 <code>css_classes</code> 和 <code>css</code>。 例如,如果您正在执行此操作</p><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Gtk<span class="token punctuation">.</span>Label</span><span class="token punctuation">(</span><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property literal-property">label</span><span class="token operator">:</span> <span class="token string">&#x27;test&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property literal-property">style</span><span class="token operator">:</span> <span class="token string">&#x27;color: gold&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>You can use the css_classes property:</p><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Gtk<span class="token punctuation">.</span>Label</span><span class="token punctuation">(</span><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property literal-property">label</span><span class="token operator">:</span> <span class="token string">&#x27;test&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property literal-property">css_classes</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">&#x27;my-label&#x27;</span><span class="token punctuation">]</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>Now you need to create a css file (For example, pref.css) for your prefs window:</p><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token punctuation">.</span><span class="token property-access">my</span><span class="token operator">-</span>label <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property literal-property">color</span><span class="token operator">:</span> gold<span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>And load it in your prefs.js file:</p><div class="relative"><pre><code class="language-javascript code-highlight"><span class="code-line"><span class="token keyword">const</span> <span class="token maybe-class-name">Me</span> <span class="token operator">=</span> imports<span class="token punctuation">.</span><span class="token property-access">misc</span><span class="token punctuation">.</span><span class="token property-access">extensionUtils</span><span class="token punctuation">.</span><span class="token property-access function method">getCurrentExtension</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">const</span> <span class="token punctuation">{</span><span class="token maybe-class-name">Gtk</span><span class="token punctuation">,</span> <span class="token maybe-class-name">Gdk</span><span class="token punctuation">}</span> <span class="token operator">=</span> imports<span class="token punctuation">.</span><span class="token property-access">gi</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">let</span> provider <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Gtk<span class="token punctuation">.</span>CssProvider</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line">provider<span class="token punctuation">.</span><span class="token property-access function method">load_from_path</span><span class="token punctuation">(</span><span class="token maybe-class-name">Me</span><span class="token punctuation">.</span><span class="token property-access">dir</span><span class="token punctuation">.</span><span class="token property-access function method">get_path</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&#x27;/prefs.css&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token maybe-class-name">Gtk</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">StyleContext</span></span><span class="token punctuation">.</span><span class="token property-access function method">add_provider_for_display</span><span class="token punctuation">(</span> </span><span class="code-line"> <span class="token maybe-class-name">Gdk</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Display</span></span><span class="token punctuation">.</span><span class="token property-access function method">get_default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> provider<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token maybe-class-name">Gtk</span><span class="token punctuation">.</span><span class="token constant">STYLE_PROVIDER_PRIORITY_APPLICATION</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><h4 id="no-packing"><a href="#no-packing" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>No Packing</h4><p>You don&#x27;t need to use packing anymore. It means instead of:</p><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>object</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>GtkBox<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>visible<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>can-focus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>False<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>child</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>placeholder</span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>child</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>object</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>packing</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>expand<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>fill<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>position<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>packing</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>You should use:</p><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>object</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>GtkBox<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>visible<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>can-focus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>False<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>hexpand<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>child</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>placeholder</span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>child</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>object</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><ul><li><p>For horizontal expand use <code>hexpand</code>.</p></li><li><p>For vertical expand use <code>vexpand</code>.</p></li><li><p>Don&#x27;t need to use <code>fill</code> property since it will be <code>true</code> by default.</p></li></ul><h4 id="no-margin-left-and-margin-right-property"><a href="#no-margin-left-and-margin-right-property" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>No margin-left and margin-right property</h4><p><code>margin-left</code> and <code>margin-right</code> property has been removed from GTK4.</p><p>You should use <code>margin-start</code> and <code>margin-end</code> instead.</p><p>关于这个改变,老灯感觉很奇怪。没有觉得 <code>margin-start</code> 会比 <code>margin-left</code> 直观。。。</p><h4 id="shadow-type"><a href="#shadow-type" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>shadow-type</h4><p>shadow-type no longer exists in GTK4 for GtkFrame, GtkViewport and GtkScrolledWindow.</p><p>Just remove the shadow-type property</p><h4 id="draw-value-property-on-gtkscale"><a href="#draw-value-property-on-gtkscale" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>draw-value property on GtkScale</h4><p>On GTK4, <a href="https://developer.gnome.org/gtk4/stable/GtkScale.html#GtkScale--draw-value">draw-value property</a> for <code>GtkScale</code> is <code>False</code> by default. Set <code>draw-value</code> as True if you want to have draw value:</p><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>object</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>GtkScale<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>visible<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>can-focus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>adjustment<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>scale_adjustment<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>round-digits<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>draw-value<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>object</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>GtkScale 是什么呢? 是一个 用于从范围中选择值的滑块小部件 (slider widget)。</p><p>“draw-value” 属性解释: Whether the current value is displayed as a string next to the slider.</p><h4 id="can-focus-property"><a href="#can-focus-property" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>can-focus property</h4><p>GTK4 与 GTK3 不同的是,在 GTK4 里,当您将对象的 <code>can-focus</code> 属性设置为 <code>False</code> 时,所有后代都无法再聚焦。 例如,这里 <code>GtkToggleButton</code> 不能被聚焦,因为 <code>GtkBox</code> 上的 <code>can-focus</code> 属性是 <code>False</code>:</p><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>object</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>GtkBox<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>visible<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>can-focus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>False<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>hexpand<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>child</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>object</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>GtkToggleButton<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>visible<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>can-focus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>object</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>child</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>object</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>要解决这个问题,您需要将 <code>GtkToggleButton</code> 的父元素 <code>GtkBox</code> 的 <code>can-focus</code> 属性设置为 <code>True</code>:</p><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>object</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>GtkBox<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>visible<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>can-focus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>hexpand<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>child</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>object</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>GtkToggleButton<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>visible<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>can-focus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>True<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>object</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>child</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>object</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>这里有非常非常多的改变,如果你需要查看全部的内容,请移步 <a href="https://gjs.guide/extensions/upgrading/gnome-shell-40.html#prefs">https://gjs.guide/extensions/upgrading/gnome-shell-40.html#prefs</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://fedoraproject.org/wiki/Changes/Gnome40">https://fedoraproject.org/wiki/Changes/Gnome40</a></p><p><a href="https://blogs.gnome.org/shell-dev/2021/03/20/extensions-rebooted-porting-your-existing-extensions-to-gnome-40/">https://blogs.gnome.org/shell-dev/2021/03/20/extensions-rebooted-porting-your-existing-extensions-to-gnome-40/</a></p><p><a href="https://gjs.guide/extensions/upgrading/gnome-shell-40.html">https://gjs.guide/extensions/upgrading/gnome-shell-40.html</a></p><p><a href="https://developer.gnome.org/gtk4/stable/">https://developer.gnome.org/gtk4/stable/</a></p><p><a href="https://gjs-docs.gnome.org/gtk40/">https://gjs-docs.gnome.org/gtk40/</a></p><p><a href="https://developer.gnome.org/gtk4/stable/gtk-migrating-3-to-4.html">https://developer.gnome.org/gtk4/stable/gtk-migrating-3-to-4.html</a></p> Sat, 26 Jun 2021 04:39:03 GMT ttyS3 GNOMEGNOME40portmigrationextensiongnome-shell https://ttys3.dev/blog/optimize-og-image-meta-tag 优化 Hugo 模板里的 og:image meta 标签 https://ttys3.dev/blog/optimize-og-image-meta-tag <p>其实我用这个标签,主要是给分享到 twitter 的时候能够让 twitter 自动抓取时生成的 card 带有缩略图。</p><p>bookmarklet 也一并分享一下吧:</p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line"><span class="token literal-property property">javascript</span><span class="token operator">:</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">var</span> <span class="token constant">D</span><span class="token operator">=</span><span class="token number">640</span><span class="token punctuation">,</span><span class="token constant">A</span><span class="token operator">=</span><span class="token number">480</span><span class="token punctuation">,</span><span class="token constant">C</span><span class="token operator">=</span>screen<span class="token punctuation">.</span><span class="token property-access">height</span><span class="token punctuation">,</span><span class="token constant">B</span><span class="token operator">=</span>screen<span class="token punctuation">.</span><span class="token property-access">width</span><span class="token punctuation">,</span><span class="token constant">H</span><span class="token operator">=</span><span class="token class-name known-class-name">Math</span><span class="token punctuation">.</span><span class="token property-access function method">round</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token constant">B</span><span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token punctuation">(</span><span class="token constant">D</span><span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token constant">G</span><span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token constant">F</span><span class="token operator">=</span><span class="token dom variable">document</span><span class="token punctuation">,</span>url<span class="token punctuation">,</span>text<span class="token punctuation">;</span> <span class="token keyword control-flow">if</span><span class="token punctuation">(</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token constant">A</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token constant">G</span><span class="token operator">=</span><span class="token class-name known-class-name">Math</span><span class="token punctuation">.</span><span class="token property-access function method">round</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token constant">C</span><span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token punctuation">(</span><span class="token constant">A</span><span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">;</span> url<span class="token operator">=</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span><span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access">location</span><span class="token punctuation">)</span><span class="token punctuation">;</span> text<span class="token operator">=</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span><span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access">getSelection</span><span class="token operator">?</span><span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access function method">getSelection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access function method">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token punctuation">(</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">selection</span><span class="token operator">?</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">selection</span><span class="token punctuation">.</span><span class="token property-access function method">createRange</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">text</span><span class="token operator">:</span><span class="token string">&#x27;&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword control-flow">if</span><span class="token punctuation">(</span>text<span class="token operator">==</span><span class="token string">&#x27;&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access function method">alert</span><span class="token punctuation">(</span><span class="token string">&#x27;Please, select text on the page first&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword control-flow">else</span><span class="token punctuation">{</span> <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access function method">open</span><span class="token punctuation">(</span><span class="token string">&#x27;http://twitter.com/share?url=&#x27;</span><span class="token operator">+</span>url<span class="token operator">+</span><span class="token string">&#x27;&amp;text=&#x27;</span><span class="token operator">+</span>text<span class="token punctuation">,</span><span class="token string">&#x27;&#x27;</span><span class="token punctuation">,</span><span class="token string">&#x27;left=&#x27;</span><span class="token operator">+</span><span class="token constant">H</span><span class="token operator">+</span><span class="token string">&#x27;,top=&#x27;</span><span class="token operator">+</span><span class="token constant">G</span><span class="token operator">+</span><span class="token string">&#x27;,width=&#x27;</span><span class="token operator">+</span><span class="token constant">D</span><span class="token operator">+</span><span class="token string">&#x27;,height=&#x27;</span><span class="token operator">+</span><span class="token constant">A</span><span class="token operator">+</span><span class="token string">&#x27;,personalbar=0,toolbar=0,scrollbars=1,resizable=1&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><h2 id="模板"><a href="#模板" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>模板</h2><p>关键的 meta 标签主要是 <code>&lt;meta name=&quot;twitter:card&quot; content=&quot;summary&quot; /&gt;</code>, twitter 官网有提供文档: <a href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started#started">https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started#started</a></p><p><code>og:</code> 开头的几个 meta 是 Open Graph protocol 要求的东西,twitter 能理解它。然后 twitter 会根据 <code>og:image</code> 来自动抓取图片用于 card 显示。</p><p>其实也没啥好说的,我写这个文章的原因在于,原来我这个模板的 <code>og:image</code> 一直是不工作的。 因为我其实主要是在用 Hugo 的 Page bunlde 来写东西,我认为这是最理想的写作方式,主要是你的文章图片会在文章自己的子目录,不会乱。</p><p>原来的模板代码是这样的:</p><div class="relative"><pre><code class="code-highlight language-go-html-template"><span class="code-line">&lt;meta property=&quot;og:image&quot; content=&quot;{{ .Param &quot;cover&quot; | absURL }}&quot;&gt; </span></code></pre></div><p>我改进之后,一个是修复了对于 Page bundle 的兼容性问题,另一个是,如果没有取到 cover 图, 就自动取文章里的第一张图片。相关代码如下:</p><div class="relative"><pre><code class="code-highlight language-go-html-template"><span class="code-line"> </span><span class="code-line">&lt;!-- Twitter Card --&gt; </span><span class="code-line">&lt;meta name=&quot;twitter:card&quot; content=&quot;summary&quot; /&gt; </span><span class="code-line">{{ with $.Site.Params.Twitter.site }} </span><span class="code-line"> &lt;meta name=&quot;twitter:site&quot; content=&quot;{{ $.Site.Params.Twitter.site }}&quot; /&gt; </span><span class="code-line">{{ end }} </span><span class="code-line">{{ with $.Site.Params.Twitter.creator }} </span><span class="code-line"> &lt;meta name=&quot;twitter:creator&quot; content=&quot;{{ if .IsHome }}{{ $.Site.Params.Twitter.creator }}{{ else if isset .Params &quot;authortwitter&quot; }}{{ .Params.authorTwitter }}{{ else }}{{ .Params.Author }}{{ end }}&quot; /&gt; </span><span class="code-line">{{ end }} </span><span class="code-line">&lt;!-- OG data --&gt; </span><span class="code-line">&lt;!-- &lt;meta property=&quot;og:locale&quot; content=&quot;{{ $.Site.Language.Lang }}&quot; /&gt; --&gt; </span><span class="code-line">&lt;meta property=&quot;og:type&quot; content=&quot;{{ if .IsPage }}article{{ else }}website{{ end }}&quot; /&gt; </span><span class="code-line">&lt;meta property=&quot;og:title&quot; content=&quot;{{ if .IsHome }}{{ $.Site.Title }}{{ else }}{{ .Title }} :: {{ $.Site.Title }}{{ end }}&quot;&gt; </span><span class="code-line">&lt;meta property=&quot;og:description&quot; content=&quot;{{ if .IsHome }}{{ $.Site.Params.Subtitle }}{{ else if .Description}}{{ .Description | plainify }}{{ else }}{{ .Summary | plainify }}{{ end }}&quot; /&gt; </span><span class="code-line">&lt;meta property=&quot;og:url&quot; content=&quot;{{ .Permalink }}&quot; /&gt; </span><span class="code-line">&lt;meta property=&quot;og:site_name&quot; content=&quot;{{ $.Site.Title }}&quot; /&gt; </span><span class="code-line">{{ if not .IsHome }} </span><span class="code-line"> </span><span class="code-line"> {{ if isset .Params &quot;cover&quot; }} </span><span class="code-line"> &lt;!-- be aware that in this context, .RelPermalink is $.Page.RelPermalink --&gt; </span><span class="code-line"> {{ printf &quot;&lt;!-- .ResourceType=%#v .File.LogicalName=%#v .RelPermalink=%#v .Permalink=%#v .Params.cover=%#v --&gt;&quot; .ResourceType $.Page.File.LogicalName .RelPermalink .Permalink .Params.cover | safeHTML }} </span><span class="code-line"> {{ if eq &quot;index.md&quot; $.Page.File.LogicalName }} </span><span class="code-line"> &lt;meta property=&quot;og:image&quot; content=&quot;{{ printf &quot;%s%s&quot; .Permalink .Params.cover }}&quot;&gt; </span><span class="code-line"> {{ else }} </span><span class="code-line"> &lt;meta property=&quot;og:image&quot; content=&quot;{{ .Param &quot;cover&quot; | absURL }}&quot;&gt; </span><span class="code-line"> {{ end }} </span><span class="code-line"> {{ else }} </span><span class="code-line"> &lt;!-- get first image as featured image in post if no cover is set --&gt; </span><span class="code-line"> {{ with (index (.Resources.ByType &quot;image&quot;) 0) }} </span><span class="code-line"> &lt;!-- be aware that in this context, .RelPermalink is resource.RelPermalink --&gt; </span><span class="code-line"> {{ printf &quot;&lt;!-- .ResourceType=%#v .File.LogicalName=%#v .Resources.ByType image .RelPermalink=%#v .Permalink=%#v --&gt;&quot; .ResourceType $.Page.File.LogicalName .RelPermalink .Permalink | safeHTML }} </span><span class="code-line"> &lt;meta property=&quot;og:image&quot; content=&quot;{{ .Permalink }}&quot;&gt; </span><span class="code-line"> {{ end }} </span><span class="code-line"> {{ end }} </span><span class="code-line"> </span><span class="code-line">{{ else }} </span><span class="code-line"> </span><span class="code-line"> {{ if isset $.Site.Params &quot;favicon&quot; }} </span><span class="code-line"> &lt;meta property=&quot;og:image&quot; content=&quot;{{ $.Site.Params.favicon | absURL }}&quot;&gt; </span><span class="code-line"> {{ else }} </span><span class="code-line"> &lt;meta property=&quot;og:image&quot; content=&quot;{{ printf &quot;img/favicon/%s.png&quot; $.Site.Params.ThemeColor | absURL }}&quot;&gt; </span><span class="code-line"> {{ end }} </span><span class="code-line"> </span><span class="code-line">{{ end }} </span><span class="code-line">&lt;meta property=&quot;og:image:width&quot; content=&quot;2048&quot;&gt; </span><span class="code-line">&lt;meta property=&quot;og:image:height&quot; content=&quot;1024&quot;&gt; </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started#started">https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started#started</a></p><p><a href="https://ogp.me/#metadata">https://ogp.me/#metadata</a></p><p><a href="https://blog.hubspot.com/marketing/open-graph-tags-facebook-twitter-linkedin">https://blog.hubspot.com/marketing/open-graph-tags-facebook-twitter-linkedin</a></p><p><a href="https://neilpatel.com/blog/open-graph-meta-tags/">https://neilpatel.com/blog/open-graph-meta-tags/</a></p> Sat, 26 Jun 2021 03:09:06 GMT ttyS3 hugotwitterogpOpen Graph protocol https://ttys3.dev/blog/rsproxy-cn-the-new-rust-crates-mirror rsproxy.cn - 字节跳动新的 Rust 镜像源 https://ttys3.dev/blog/rsproxy-cn-the-new-rust-crates-mirror <p>刚从 Rust.cc 日报看到的。欢呼ing!</p><h2 id="crateio-mirror"><a href="#crateio-mirror" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Crate.io Mirror</h2><p><code>~/.cargo/config</code>:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source.crates-io</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">replace-with</span> <span class="token punctuation">=</span> <span class="token string">&#x27;rsproxy&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source.rsproxy</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">registry</span> <span class="token punctuation">=</span> <span class="token string">&quot;https://rsproxy.cn/crates.io-index&quot;</span> </span></code></pre></div><p>Rustup Mirror</p><p><code>~/.zshrc</code> or <code>~/.bashrc</code>:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token class-name builtin">export</span> <span class="token assign-left variable">RUSTUP_DIST_SERVER</span><span class="token operator">=</span><span class="token string">&quot;https://rsproxy.cn&quot;</span> </span><span class="code-line"><span class="token class-name builtin">export</span> <span class="token assign-left variable">RUSTUP_UPDATE_ROOT</span><span class="token operator">=</span><span class="token string">&quot;https://rsproxy.cn/rustup&quot;</span> </span></code></pre></div><p>官网: <a href="https://rsproxy.cn/">https://rsproxy.cn/</a></p> Fri, 25 Jun 2021 13:58:13 GMT ttyS3 rustcratesmirror https://ttys3.dev/blog/paru-aur-helper-does-not-rebuild-kernel-module-package-after-kernel-upgraded paru 不会在内核更新之后自动重建包含内核模块的包 https://ttys3.dev/blog/paru-aur-helper-does-not-rebuild-kernel-module-package-after-kernel-upgraded <p><code>paru</code> 和 <code>yay</code> 一样,是一个 aur helper.</p><p>最近用 paru 安装一个叫 <code>ipt_ndpi</code> 的包,里面包含了 iptables 扩展和内核模块。</p><p>当前内核是从 5.12.10 升级到 5.12.11 的:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">uname</span> <span class="token variable parameter">-a</span> </span><span class="code-line">Linux wudeng <span class="token number">5.12</span>.11-arch1-1 <span class="token comment">#1 SMP PREEMPT Wed, 16 Jun 2021 15:25:28 +0000 x86_64 GNU/Linux</span> </span><span class="code-line"> </span><span class="code-line">❯ paru <span class="token variable parameter">-V</span> </span><span class="code-line">paru v1.7.2 +git - libalpm v13.0.0 </span></code></pre></div><p>尝试重新安装:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">🔴 <span class="token number">1</span> ❯ paru <span class="token variable parameter">-S</span> ipt_ndpi </span><span class="code-line">:: Resolving dependencies<span class="token punctuation">..</span>. </span><span class="code-line">:: Calculating conflicts<span class="token punctuation">..</span>. </span><span class="code-line">:: Calculating inner conflicts<span class="token punctuation">..</span>. </span><span class="code-line"> </span><span class="code-line">Aur <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> ipt_ndpi-1.2_3.2.0.2224.8a19d7e3-1 </span><span class="code-line"> </span><span class="code-line">:: Proceed to review? <span class="token punctuation">[</span>Y/n<span class="token punctuation">]</span>: y </span><span class="code-line"> </span><span class="code-line">:: Downloading PKGBUILDs<span class="token punctuation">..</span>. </span><span class="code-line"> PKGBUILDs up to <span class="token function">date</span> </span><span class="code-line">:: Proceed with installation? <span class="token punctuation">[</span>Y/n<span class="token punctuation">]</span>: y </span><span class="code-line">fetching devel info<span class="token punctuation">..</span>. </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Making package: ipt_ndpi <span class="token number">1</span>.2_3.5.0.3243.640643d9-1 <span class="token punctuation">(</span>Fri <span class="token number">18</span> Jun <span class="token number">2021</span> <span class="token number">11</span>:27:46 PM CST<span class="token punctuation">)</span> </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Retrieving sources<span class="token punctuation">..</span>. </span><span class="code-line"> -<span class="token operator">&gt;</span> Updating ipt_ndpi <span class="token function">git</span> repo<span class="token punctuation">..</span>. </span><span class="code-line">Fetching origin </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Validating <span class="token builtin class-name">source</span> files with sha256sums<span class="token punctuation">..</span>. </span><span class="code-line"> ipt_ndpi <span class="token punctuation">..</span>. Skipped </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Making package: ipt_ndpi <span class="token number">1</span>.2_3.5.0.3243.640643d9-1 <span class="token punctuation">(</span>Fri <span class="token number">18</span> Jun <span class="token number">2021</span> <span class="token number">11</span>:27:50 PM CST<span class="token punctuation">)</span> </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Checking runtime dependencies<span class="token punctuation">..</span>. </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Checking buildtime dependencies<span class="token punctuation">..</span>. </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Retrieving sources<span class="token punctuation">..</span>. </span><span class="code-line"> -<span class="token operator">&gt;</span> Updating ipt_ndpi <span class="token function">git</span> repo<span class="token punctuation">..</span>. </span><span class="code-line">Fetching origin </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Validating <span class="token builtin class-name">source</span> files with sha256sums<span class="token punctuation">..</span>. </span><span class="code-line"> ipt_ndpi <span class="token punctuation">..</span>. Skipped </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Removing existing <span class="token variable">$srcdir</span>/ directory<span class="token punctuation">..</span>. </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Extracting sources<span class="token punctuation">..</span>. </span><span class="code-line"> -<span class="token operator">&gt;</span> Creating working copy of ipt_ndpi <span class="token function">git</span> repo<span class="token punctuation">..</span>. </span><span class="code-line">Cloning into <span class="token string">&#x27;ipt_ndpi&#x27;</span><span class="token punctuation">..</span>. </span><span class="code-line">done. </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Starting prepare<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">..</span>. </span><span class="code-line">Already on <span class="token string">&#x27;flow_info-3.2&#x27;</span> </span><span class="code-line">Your branch is up to <span class="token function">date</span> with <span class="token string">&#x27;origin/flow_info-3.2&#x27;</span><span class="token builtin class-name">.</span> </span><span class="code-line">autoreconf: <span class="token builtin class-name">export</span> <span class="token variable assign-left">WARNINGS</span><span class="token operator">=</span> </span><span class="code-line">autoreconf: Entering directory <span class="token string">&#x27;.&#x27;</span> </span><span class="code-line">autoreconf: configure.ac: not using Gettext </span><span class="code-line">autoreconf: running: aclocal <span class="token variable parameter">--force</span> <span class="token variable parameter">-I</span> m4 </span><span class="code-line">autoreconf: configure.ac: tracing </span><span class="code-line">autoreconf: running: libtoolize <span class="token variable parameter">--copy</span> <span class="token variable parameter">--force</span> </span><span class="code-line">libtoolize: putting auxiliary files <span class="token keyword">in</span> AC_CONFIG_AUX_DIR, <span class="token string">&#x27;.&#x27;</span><span class="token builtin class-name">.</span> </span><span class="code-line">libtoolize: copying <span class="token function">file</span> <span class="token string">&#x27;./ltmain.sh&#x27;</span> </span><span class="code-line">libtoolize: putting macros <span class="token keyword">in</span> AC_CONFIG_MACRO_DIRS, <span class="token string">&#x27;m4&#x27;</span><span class="token builtin class-name">.</span> </span><span class="code-line">libtoolize: copying <span class="token function">file</span> <span class="token string">&#x27;m4/libtool.m4&#x27;</span> </span><span class="code-line">libtoolize: copying <span class="token function">file</span> <span class="token string">&#x27;m4/ltoptions.m4&#x27;</span> </span><span class="code-line">libtoolize: copying <span class="token function">file</span> <span class="token string">&#x27;m4/ltsugar.m4&#x27;</span> </span><span class="code-line">libtoolize: copying <span class="token function">file</span> <span class="token string">&#x27;m4/ltversion.m4&#x27;</span> </span><span class="code-line">libtoolize: copying <span class="token function">file</span> <span class="token string">&#x27;m4/lt~obsolete.m4&#x27;</span> </span><span class="code-line">autoreconf: configure.ac: not using Intltool </span><span class="code-line">autoreconf: configure.ac: not using Gtkdoc </span><span class="code-line">autoreconf: running: aclocal <span class="token variable parameter">--force</span> <span class="token variable parameter">-I</span> m4 </span><span class="code-line">autoreconf: running: /usr/bin/autoconf <span class="token variable parameter">--force</span> </span><span class="code-line">configure.ac:41: warning: The macro <span class="token variable"><span class="token variable">`</span>AC_PROG_CC_STDC&#x27; is obsolete. </span></span><span class="code-line"><span class="token variable">configure.ac:41: You should run autoupdate. </span></span><span class="code-line"><span class="token variable">./lib/autoconf/c.m4:1666: AC_PROG_CC_STDC is expanded from<span class="token punctuation">..</span>. </span></span><span class="code-line"><span class="token variable">configure.ac:41: the <span class="token function">top</span> level </span></span><span class="code-line"><span class="token variable">configure.ac:46: warning: The macro <span class="token variable">`</span></span>AC_PROG_CC_STDC<span class="token string">&#x27; is obsolete. </span></span><span class="code-line"><span class="token string">configure.ac:46: You should run autoupdate. </span></span><span class="code-line"><span class="token string">./lib/autoconf/c.m4:1666: AC_PROG_CC_STDC is expanded from... </span></span><span class="code-line"><span class="token string">configure.ac:46: the top level </span></span><span class="code-line"><span class="token string">configure.ac:49: warning: $as_echo is obsolete; use AS_ECHO([&quot;message&quot;]) instead </span></span><span class="code-line"><span class="token string">lib/m4sugar/m4sh.m4:692: _AS_IF_ELSE is expanded from... </span></span><span class="code-line"><span class="token string">lib/m4sugar/m4sh.m4:699: AS_IF is expanded from... </span></span><span class="code-line"><span class="token string">./lib/autoconf/general.m4:2249: AC_CACHE_VAL is expanded from... </span></span><span class="code-line"><span class="token string">./lib/autoconf/general.m4:2270: AC_CACHE_CHECK is expanded from... </span></span><span class="code-line"><span class="token string">m4/ax_pthread.m4:88: AX_PTHREAD is expanded from... </span></span><span class="code-line"><span class="token string">configure.ac:49: the top level </span></span><span class="code-line"><span class="token string">configure.ac:232: warning: The macro `AC_HAVE_HEADERS&#x27;</span> is obsolete. </span><span class="code-line">configure.ac:232: You should run autoupdate. </span><span class="code-line">./lib/autoconf/oldnames.m4:35: AC_HAVE_HEADERS is expanded from<span class="token punctuation">..</span>. </span><span class="code-line">configure.ac:232: the <span class="token function">top</span> level </span><span class="code-line">autoreconf: running: /usr/bin/autoheader <span class="token variable parameter">--force</span> </span><span class="code-line">autoreconf: running: automake --add-missing <span class="token variable parameter">--copy</span> --force-missing </span><span class="code-line">configure.ac:34: installing <span class="token string">&#x27;./compile&#x27;</span> </span><span class="code-line">configure.ac:34: installing <span class="token string">&#x27;./config.guess&#x27;</span> </span><span class="code-line">configure.ac:34: installing <span class="token string">&#x27;./config.sub&#x27;</span> </span><span class="code-line">configure.ac:6: installing <span class="token string">&#x27;./install-sh&#x27;</span> </span><span class="code-line">configure.ac:6: installing <span class="token string">&#x27;./missing&#x27;</span> </span><span class="code-line">fuzz/Makefile.am: installing <span class="token string">&#x27;./depcomp&#x27;</span> </span><span class="code-line">parallel-tests: installing <span class="token string">&#x27;./test-driver&#x27;</span> </span><span class="code-line">autoreconf: <span class="token string">&#x27;./config.sub&#x27;</span> is updated </span><span class="code-line">autoreconf: <span class="token string">&#x27;./config.guess&#x27;</span> is updated </span><span class="code-line">autoreconf: Leaving directory <span class="token string">&#x27;.&#x27;</span> </span><span class="code-line">./configure </span><span class="code-line">checking <span class="token keyword">for</span> a BSD-compatible install<span class="token punctuation">..</span>. /usr/bin/install <span class="token variable parameter">-c</span> </span><span class="code-line">checking whether build environment is sane<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> a race-free <span class="token function">mkdir</span> -p<span class="token punctuation">..</span>. /usr/bin/mkdir <span class="token variable parameter">-p</span> </span><span class="code-line">checking <span class="token keyword">for</span> gawk<span class="token punctuation">..</span>. <span class="token function">gawk</span> </span><span class="code-line">checking whether <span class="token function">make</span> sets <span class="token variable"><span class="token variable">$(</span>MAKE<span class="token variable">)</span></span><span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking whether <span class="token function">make</span> supports nested variables<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking build system type<span class="token punctuation">..</span>. x86_64-pc-linux-gnu </span><span class="code-line">checking <span class="token function">host</span> system type<span class="token punctuation">..</span>. x86_64-pc-linux-gnu </span><span class="code-line">checking how to print strings<span class="token punctuation">..</span>. <span class="token builtin class-name">printf</span> </span><span class="code-line">checking whether <span class="token function">make</span> supports the include directive<span class="token punctuation">..</span>. <span class="token function">yes</span> <span class="token punctuation">(</span>GNU style<span class="token punctuation">)</span> </span><span class="code-line">checking <span class="token keyword">for</span> gcc<span class="token punctuation">..</span>. gcc </span><span class="code-line">checking whether the C compiler works<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> C compiler default output <span class="token function">file</span> name<span class="token punctuation">..</span>. a.out </span><span class="code-line">checking <span class="token keyword">for</span> suffix of executables<span class="token punctuation">..</span>. </span><span class="code-line">checking whether we are cross compiling<span class="token punctuation">..</span>. no </span><span class="code-line">checking <span class="token keyword">for</span> suffix of object files<span class="token punctuation">..</span>. o </span><span class="code-line">checking whether the compiler supports GNU C<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking whether gcc accepts -g<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> gcc option to <span class="token builtin class-name">enable</span> C11 features<span class="token punctuation">..</span>. none needed </span><span class="code-line">checking whether gcc understands <span class="token variable parameter">-c</span> and <span class="token variable parameter">-o</span> together<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking dependency style of gcc<span class="token punctuation">..</span>. gcc3 </span><span class="code-line">checking <span class="token keyword">for</span> a <span class="token function">sed</span> that does not truncate output<span class="token punctuation">..</span>. /usr/bin/sed </span><span class="code-line">checking <span class="token keyword">for</span> <span class="token function">grep</span> that handles long lines and -e<span class="token punctuation">..</span>. /usr/bin/grep </span><span class="code-line">checking <span class="token keyword">for</span> egrep<span class="token punctuation">..</span>. /usr/bin/grep <span class="token variable parameter">-E</span> </span><span class="code-line">checking <span class="token keyword">for</span> fgrep<span class="token punctuation">..</span>. /usr/bin/grep <span class="token variable parameter">-F</span> </span><span class="code-line">checking <span class="token keyword">for</span> ld used by gcc<span class="token punctuation">..</span>. /usr/bin/ld </span><span class="code-line">checking <span class="token keyword">if</span> the linker <span class="token punctuation">(</span>/usr/bin/ld<span class="token punctuation">)</span> is GNU ld<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> BSD- or MS-compatible name lister <span class="token punctuation">(</span>nm<span class="token punctuation">)</span><span class="token punctuation">..</span>. /usr/bin/nm <span class="token variable parameter">-B</span> </span><span class="code-line">checking the name lister <span class="token punctuation">(</span>/usr/bin/nm -B<span class="token punctuation">)</span> interface<span class="token punctuation">..</span>. BSD nm </span><span class="code-line">checking whether <span class="token function">ln</span> <span class="token variable parameter">-s</span> works<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking the maximum length of <span class="token builtin class-name">command</span> line arguments<span class="token punctuation">..</span>. <span class="token number">1572864</span> </span><span class="code-line">checking how to convert x86_64-pc-linux-gnu <span class="token function">file</span> names to x86_64-pc-linux-gnu format<span class="token punctuation">..</span>. func_convert_file_noop </span><span class="code-line">checking how to convert x86_64-pc-linux-gnu <span class="token function">file</span> names to toolchain format<span class="token punctuation">..</span>. func_convert_file_noop </span><span class="code-line">checking <span class="token keyword">for</span> /usr/bin/ld option to reload object files<span class="token punctuation">..</span>. <span class="token variable parameter">-r</span> </span><span class="code-line">checking <span class="token keyword">for</span> objdump<span class="token punctuation">..</span>. objdump </span><span class="code-line">checking how to recognize dependent libraries<span class="token punctuation">..</span>. pass_all </span><span class="code-line">checking <span class="token keyword">for</span> dlltool<span class="token punctuation">..</span>. no </span><span class="code-line">checking how to associate runtime and <span class="token function">link</span> libraries<span class="token punctuation">..</span>. <span class="token builtin class-name">printf</span> %s<span class="token punctuation">\</span>n </span><span class="code-line">checking <span class="token keyword">for</span> ar<span class="token punctuation">..</span>. ar </span><span class="code-line">checking <span class="token keyword">for</span> archiver @FILE support<span class="token punctuation">..</span>. @ </span><span class="code-line">checking <span class="token keyword">for</span> strip<span class="token punctuation">..</span>. strip </span><span class="code-line">checking <span class="token keyword">for</span> ranlib<span class="token punctuation">..</span>. ranlib </span><span class="code-line">checking <span class="token builtin class-name">command</span> to parse /usr/bin/nm <span class="token variable parameter">-B</span> output from gcc object<span class="token punctuation">..</span>. ok </span><span class="code-line">checking <span class="token keyword">for</span> sysroot<span class="token punctuation">..</span>. no </span><span class="code-line">checking <span class="token keyword">for</span> a working dd<span class="token punctuation">..</span>. /usr/bin/dd </span><span class="code-line">checking how to truncate binary pipes<span class="token punctuation">..</span>. /usr/bin/dd <span class="token variable assign-left">bs</span><span class="token operator">=</span><span class="token number">4096</span> <span class="token variable assign-left">count</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line">checking <span class="token keyword">for</span> mt<span class="token punctuation">..</span>. no </span><span class="code-line">checking <span class="token keyword">if</span> <span class="token builtin class-name">:</span> is a manifest tool<span class="token punctuation">..</span>. no </span><span class="code-line">checking <span class="token keyword">for</span> stdio.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> stdlib.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> string.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> inttypes.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> stdint.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> strings.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> sys/stat.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> sys/types.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> unistd.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> dlfcn.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> objdir<span class="token punctuation">..</span>. .libs </span><span class="code-line">checking <span class="token keyword">if</span> gcc supports -fno-rtti -fno-exceptions<span class="token punctuation">..</span>. no </span><span class="code-line">checking <span class="token keyword">for</span> gcc option to produce PIC<span class="token punctuation">..</span>. <span class="token variable parameter">-fPIC</span> <span class="token variable parameter">-DPIC</span> </span><span class="code-line">checking <span class="token keyword">if</span> gcc PIC flag <span class="token variable parameter">-fPIC</span> <span class="token variable parameter">-DPIC</span> works<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">if</span> gcc static flag <span class="token variable parameter">-static</span> works<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">if</span> gcc supports <span class="token variable parameter">-c</span> <span class="token variable parameter">-o</span> file.o<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">if</span> gcc supports <span class="token variable parameter">-c</span> <span class="token variable parameter">-o</span> file.o<span class="token punctuation">..</span>. <span class="token punctuation">(</span>cached<span class="token punctuation">)</span> <span class="token function">yes</span> </span><span class="code-line">checking whether the gcc linker <span class="token punctuation">(</span>/usr/bin/ld <span class="token variable parameter">-m</span> elf_x86_64<span class="token punctuation">)</span> supports shared libraries<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking whether <span class="token variable parameter">-lc</span> should be explicitly linked in<span class="token punctuation">..</span>. no </span><span class="code-line">checking dynamic linker characteristics<span class="token punctuation">..</span>. GNU/Linux ld.so </span><span class="code-line">checking how to hardcode library paths into programs<span class="token punctuation">..</span>. immediate </span><span class="code-line">checking whether stripping libraries is possible<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">if</span> libtool supports shared libraries<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking whether to build shared libraries<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking whether to build static libraries<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> g++<span class="token punctuation">..</span>. g++ </span><span class="code-line">checking whether the compiler supports GNU C++<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking whether g++ accepts -g<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> g++ option to <span class="token builtin class-name">enable</span> C++11 features<span class="token punctuation">..</span>. none needed </span><span class="code-line">checking dependency style of g++<span class="token punctuation">..</span>. gcc3 </span><span class="code-line">checking how to run the C preprocessor<span class="token punctuation">..</span>. gcc <span class="token variable parameter">-E</span> </span><span class="code-line">checking whether gcc is Clang<span class="token punctuation">..</span>. no </span><span class="code-line">checking whether pthreads work with -pthread<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> joinable pthread attribute<span class="token punctuation">..</span>. PTHREAD_CREATE_JOINABLE </span><span class="code-line">checking whether <span class="token function">more</span> special flags are required <span class="token keyword">for</span> pthreads<span class="token punctuation">..</span>. no </span><span class="code-line">checking <span class="token keyword">for</span> PTHREAD_PRIO_INHERIT<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> pkg-config<span class="token punctuation">..</span>. /usr/bin/pkg-config </span><span class="code-line">checking pkg-config is at least version <span class="token number">0.9</span>.0<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> JSONC<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> netinet/in.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> stdint.h<span class="token punctuation">..</span>. <span class="token punctuation">(</span>cached<span class="token punctuation">)</span> <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> stdlib.h<span class="token punctuation">..</span>. <span class="token punctuation">(</span>cached<span class="token punctuation">)</span> <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> string.h<span class="token punctuation">..</span>. <span class="token punctuation">(</span>cached<span class="token punctuation">)</span> <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> unistd.h<span class="token punctuation">..</span>. <span class="token punctuation">(</span>cached<span class="token punctuation">)</span> <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> json.h<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking DPDK <span class="token punctuation">(</span>used by ndpiReader<span class="token punctuation">)</span><span class="token punctuation">..</span>. no <span class="token punctuation">(</span>missing /home/ttys3/DPDK<span class="token punctuation">)</span> </span><span class="code-line">checking <span class="token keyword">for</span> <span class="token variable for-or-select">numa_available</span> <span class="token keyword">in</span> -lnuma<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> <span class="token variable for-or-select">pcap_open_live</span> <span class="token keyword">in</span> -lpcap<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> <span class="token variable for-or-select">pthread_setaffinity_np</span> <span class="token keyword">in</span> -lpthread<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking <span class="token keyword">for</span> <span class="token variable for-or-select">gcry_cipher_checktag</span> <span class="token keyword">in</span> -lgcrypt<span class="token punctuation">..</span>. <span class="token function">yes</span> </span><span class="code-line">checking that generated files are newer than configure<span class="token punctuation">..</span>. <span class="token keyword">done</span> </span><span class="code-line">configure: creating ./config.status </span><span class="code-line">config.status: creating Makefile </span><span class="code-line">config.status: creating example/Makefile </span><span class="code-line">config.status: creating example/Makefile.dpdk </span><span class="code-line">config.status: creating tests/Makefile </span><span class="code-line">config.status: creating tests/unit/Makefile </span><span class="code-line">config.status: creating tests/dga/Makefile </span><span class="code-line">config.status: creating libndpi.pc </span><span class="code-line">config.status: creating src/include/ndpi_define.h </span><span class="code-line">config.status: creating src/lib/Makefile </span><span class="code-line">config.status: creating python/Makefile </span><span class="code-line">config.status: creating fuzz/Makefile </span><span class="code-line">config.status: creating src/include/ndpi_api.h </span><span class="code-line">config.status: creating tests/do.sh </span><span class="code-line">config.status: creating tests/do_valgrind.sh </span><span class="code-line">config.status: creating src/include/ndpi_config.h </span><span class="code-line">config.status: executing depfiles commands </span><span class="code-line">config.status: executing libtool commands </span><span class="code-line"><span class="token variable assign-left">depbase</span><span class="token operator">=</span><span class="token variable"><span class="token variable">`</span><span class="token builtin class-name">echo</span> ndpi_network_list_compile.o <span class="token operator">|</span> <span class="token function">sed</span> <span class="token string">&#x27;s|[^/]*$|.deps/&amp;|;s|\.o$||&#x27;</span><span class="token variable">`</span></span><span class="token punctuation">;</span><span class="token punctuation">\</span> </span><span class="code-line">gcc <span class="token variable parameter">-DHAVE_CONFIG_H</span> -I. -I<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/src/include -I<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/src/include/ -I<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/src/lib/third_party/include/ <span class="token variable parameter">-g</span> <span class="token variable parameter">-O2</span> -I/usr/include/json-c <span class="token variable parameter">-fPIC</span> <span class="token variable parameter">-DPIC</span> <span class="token variable parameter">-DNDPI_LIB_COMPILATION</span> <span class="token variable parameter">-MT</span> ndpi_network_list_compile.o <span class="token variable parameter">-MD</span> <span class="token variable parameter">-MP</span> <span class="token variable parameter">-MF</span> <span class="token variable">$depbase</span>.Tpo <span class="token variable parameter">-c</span> <span class="token variable parameter">-o</span> ndpi_network_list_compile.o ndpi_network_list_compile.c <span class="token operator">&amp;&amp;</span><span class="token punctuation">\</span> </span><span class="code-line"><span class="token function">mv</span> <span class="token variable parameter">-f</span> <span class="token variable">$depbase</span>.Tpo <span class="token variable">$depbase</span>.Po </span><span class="code-line">/bin/sh <span class="token punctuation">..</span>/<span class="token punctuation">..</span>/libtool <span class="token variable parameter">--tag</span><span class="token operator">=</span>CC <span class="token variable parameter">--mode</span><span class="token operator">=</span>link gcc <span class="token variable parameter">-g</span> <span class="token variable parameter">-O2</span> -I/usr/include/json-c <span class="token variable parameter">-fPIC</span> <span class="token variable parameter">-DPIC</span> <span class="token variable parameter">-DNDPI_LIB_COMPILATION</span> <span class="token variable parameter">-o</span> ndpi_network_list_compile ndpi_network_list_compile.o <span class="token variable parameter">-lgcrypt</span> -ljson-c </span><span class="code-line">libtool: link: gcc <span class="token variable parameter">-g</span> <span class="token variable parameter">-O2</span> -I/usr/include/json-c <span class="token variable parameter">-fPIC</span> <span class="token variable parameter">-DPIC</span> <span class="token variable parameter">-DNDPI_LIB_COMPILATION</span> <span class="token variable parameter">-o</span> ndpi_network_list_compile ndpi_network_list_compile.o <span class="token variable parameter">-lgcrypt</span> -ljson-c </span><span class="code-line">./ndpi_network_list_compile <span class="token variable parameter">-o</span> ndpi_network_list.c.inc ndpi_network_list_amazon.yaml ndpi_network_list_std.yaml ndpi_network_list_tor.yaml ndpi_network_list_whatsapp.yaml </span><span class="code-line">Warning: line <span class="token number">814</span>: <span class="token string">&#x27;209.148.214.135/21&#x27;</span> is not network <span class="token punctuation">(</span>NETFLIX<span class="token punctuation">)</span> </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Starting pkgver<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">..</span>. </span><span class="code-line">gawk: cmd. line:1: warning: regexp escape sequence <span class="token variable"><span class="token variable">`</span><span class="token punctuation">\</span>&quot;&#x27; is not a known regexp operator </span></span><span class="code-line"><span class="token variable">gawk: cmd. line:1: warning: regexp escape sequence <span class="token variable">`</span></span><span class="token punctuation">\</span>&quot;&#x27; is not a known regexp operator </span><span class="code-line"><span class="token operator">==</span><span class="token operator">&gt;</span> Sources are ready. </span><span class="code-line">ipt_ndpi-1.2_3.2.0.2224.8a19d7e3-1: parsing pkg list<span class="token punctuation">..</span>. </span><span class="code-line">:: ipt_ndpi-1.2_3.2.0.2224.8a19d7e3-1 is up to <span class="token function">date</span> -- skipping build </span><span class="code-line">loading packages<span class="token punctuation">..</span>. </span><span class="code-line">warning: ipt_ndpi-1.2_3.5.0.3243.640643d9-1 is up to <span class="token function">date</span> -- reinstalling </span><span class="code-line">resolving dependencies<span class="token punctuation">..</span>. </span><span class="code-line">looking <span class="token keyword">for</span> conflicting packages<span class="token punctuation">..</span>. </span><span class="code-line"> </span><span class="code-line">Package <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> Old Version New Version Net Change </span><span class="code-line"> </span><span class="code-line">ipt_ndpi <span class="token number">1</span>.2_3.5.0.3243.640643d9-1 <span class="token number">1</span>.2_3.5.0.3243.640643d9-1 <span class="token number">0.00</span> MiB </span><span class="code-line"> </span><span class="code-line">Total Installed Size: <span class="token number">3.18</span> MiB </span><span class="code-line">Net Upgrade Size: <span class="token number">0.00</span> MiB </span><span class="code-line"> </span><span class="code-line">:: Proceed with installation? <span class="token punctuation">[</span>Y/n<span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> checking keys <span class="token keyword">in</span> keyring <span class="token punctuation">[</span><span class="token comment">###################################] 100%</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> checking package integrity <span class="token punctuation">[</span><span class="token comment">###################################] 100%</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> loading package files <span class="token punctuation">[</span><span class="token comment">###################################] 100%</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> checking <span class="token keyword">for</span> <span class="token function">file</span> conflicts <span class="token punctuation">[</span><span class="token comment">###################################] 100%</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> checking available disk space <span class="token punctuation">[</span><span class="token comment">###################################] 100%</span> </span><span class="code-line">warning: could not get <span class="token function">file</span> information <span class="token keyword">for</span> usr/lib/modules/5.12.10-arch1-1/ </span><span class="code-line">warning: could not get <span class="token function">file</span> information <span class="token keyword">for</span> usr/lib/modules/5.12.10-arch1-1/extra/ </span><span class="code-line">warning: could not get <span class="token function">file</span> information <span class="token keyword">for</span> usr/lib/modules/5.12.10-arch1-1/extra/xt_ndpi.ko.gz </span><span class="code-line">:: Processing package changes<span class="token punctuation">..</span>. </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> reinstalling ipt_ndpi <span class="token punctuation">[</span><span class="token comment">###################################] 100%</span> </span><span class="code-line">:: Running post-transaction hooks<span class="token punctuation">..</span>. </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/3<span class="token punctuation">)</span> Arming ConditionNeedsUpdate<span class="token punctuation">..</span>. </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">2</span>/3<span class="token punctuation">)</span> Updating module dependencies<span class="token punctuation">..</span>. </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">3</span>/3<span class="token punctuation">)</span> Refreshing PackageKit<span class="token punctuation">..</span>. </span><span class="code-line"> ~ took 26s </span></code></pre></div><p>可以发现包还是被安装到了 旧内核目录: <code>5.12.10-arch1-1</code></p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"> /usr/lib/modules  </span><span class="code-line">❯ ll </span><span class="code-line">drwxr-xr-x root root <span class="token number">4.0</span> KB Fri Jun <span class="token number">18</span> <span class="token number">23</span>:28:01 <span class="token number">2021</span>  <span class="token number">5.12</span>.10-arch1-1 </span><span class="code-line">drwxr-xr-x root root <span class="token number">4.0</span> KB Fri Jun <span class="token number">18</span> 02:12:44 <span class="token number">2021</span>  <span class="token number">5.12</span>.11-arch1-1 </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"> /usr/lib/modules  </span><span class="code-line">❯ tree <span class="token number">5.12</span>.10-arch1-1 </span><span class="code-line"><span class="token number">5.12</span>.10-arch1-1 </span><span class="code-line">└── extra </span><span class="code-line"> └── xt_ndpi.ko.gz </span><span class="code-line"> </span><span class="code-line"><span class="token number">1</span> directory, <span class="token number">1</span> <span class="token function">file</span> </span><span class="code-line"> </span><span class="code-line">❯ tree <span class="token variable parameter">-L</span> <span class="token number">1</span> <span class="token number">5.12</span>.11-arch1-1 </span><span class="code-line"><span class="token number">5.12</span>.11-arch1-1 </span><span class="code-line">├── build </span><span class="code-line">├── extramodules </span><span class="code-line">├── kernel </span><span class="code-line">├── modules.alias </span><span class="code-line">├── modules.alias.bin </span><span class="code-line">├── modules.builtin </span><span class="code-line">├── modules.builtin.alias.bin </span><span class="code-line">├── modules.builtin.bin </span><span class="code-line">├── modules.builtin.modinfo </span><span class="code-line">├── modules.dep </span><span class="code-line">├── modules.dep.bin </span><span class="code-line">├── modules.devname </span><span class="code-line">├── modules.order </span><span class="code-line">├── modules.softdep </span><span class="code-line">├── modules.symbols </span><span class="code-line">├── modules.symbols.bin </span><span class="code-line">├── pkgbase </span><span class="code-line">└── vmlinuz </span><span class="code-line"> </span><span class="code-line"><span class="token number">3</span> directories, <span class="token number">15</span> files </span></code></pre></div><p>然后我仔细观察了下 paru 输出的信息,里面有关键的:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token operator">:</span><span class="token operator">:</span> ipt_ndpi<span class="token operator">-</span><span class="token number">1.2_3</span><span class="token number">.2</span><span class="token number">.0</span><span class="token number">.2224</span><span class="token punctuation">.</span>8a19d7e3<span class="token operator">-</span><span class="token number">1</span> is up to date <span class="token operator">--</span> skipping build </span><span class="code-line">loading packages<span class="token operator spread">...</span> </span><span class="code-line"><span class="token literal-property property">warning</span><span class="token operator">:</span> ipt_ndpi<span class="token operator">-</span><span class="token number">1.2_3</span><span class="token number">.5</span><span class="token number">.0</span><span class="token number">.3243</span><span class="token punctuation">.</span>640643d9<span class="token operator">-</span><span class="token number">1</span> is up to date <span class="token operator">--</span> reinstalling </span></code></pre></div><p>然后我仔细观察了下这个 <a href="https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=ipt_ndpi">PKGBUILD</a>:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># Maintainer: Shalygin Konstantin &lt;[email protected]&gt;</span> </span><span class="code-line"><span class="token comment"># Contributor: Shalygin Konstantin &lt;[email protected]&gt;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token variable assign-left">pkgname</span><span class="token operator">=</span><span class="token string">&#x27;ipt_ndpi&#x27;</span> </span><span class="code-line"><span class="token variable assign-left">pkgver</span><span class="token operator">=</span><span class="token number">1</span>.2_3.2.0.2224.8a19d7e3 </span><span class="code-line"><span class="token variable assign-left">pkgrel</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">pkgdesc</span><span class="token operator">=</span><span class="token string">&#x27;nDPI as netfilter extension.&#x27;</span> </span><span class="code-line"><span class="token variable assign-left">arch</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;any&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">url</span><span class="token operator">=</span><span class="token string">&#x27;https://github.com/vel21ripn/nDPI&#x27;</span> </span><span class="code-line"><span class="token variable assign-left">license</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;GPL&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">depends</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;iptables&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">makedepends</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;git&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">source</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&quot;<span class="token variable">${pkgname}</span>::git+<span class="token variable">${url}</span>&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">sha256sums</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;SKIP&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token comment"># define &#x27;-lts&#x27; for linux-lts package</span> </span><span class="code-line"><span class="token variable assign-left">_linux_custom</span><span class="token operator">=</span><span class="token string">&quot;&quot;</span> </span><span class="code-line"><span class="token variable assign-left">_kernver</span><span class="token operator">=</span><span class="token string">&quot;<span class="token variable"><span class="token variable">`</span>pacman <span class="token variable parameter">-Ql</span> linux$<span class="token punctuation">{</span>_linux_custom<span class="token punctuation">}</span> <span class="token operator">|</span> <span class="token function">awk</span> <span class="token string">&#x27;/(\/modules\/)([0-9.-])+-(.*)&#x27;</span>$<span class="token punctuation">{</span>_linux_custom<span class="token punctuation">}</span><span class="token string">&#x27;\/$/ {print $2}&#x27;</span> <span class="token operator">|</span> <span class="token function">head</span> <span class="token variable parameter">-n1</span><span class="token variable">`</span></span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">pkgver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">${srcdir}</span>/<span class="token variable">${pkgname}</span>&quot;</span> </span><span class="code-line"> <span class="token variable assign-left">ndpi_version</span><span class="token operator">=</span><span class="token variable"><span class="token variable">`</span><span class="token function">gawk</span> <span class="token string">&#x27;match($0, /pr_info\(&quot;xt_ndpi\sv([0-9.]+)\sndpi\s%s\&quot;$/, a) {print a[1]}&#x27;</span> ndpi-netfilter/src/main.c<span class="token variable">`</span></span> </span><span class="code-line"> <span class="token variable assign-left">git_version</span><span class="token operator">=</span><span class="token variable"><span class="token variable">`</span><span class="token function">gawk</span> <span class="token string">&#x27;match($0, /^(#define)\s(NDPI_GIT_RELEASE)\s(\&quot;)([a-z0-9.-]+)(\&quot;)$/, a) {print a[4]}&#x27;</span> src/include/ndpi_config.h <span class="token operator">|</span> <span class="token function">sed</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s/-/./g&#x27;</span><span class="token variable">`</span></span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-e</span> <span class="token string">&quot;<span class="token variable">${ndpi_version}</span>_<span class="token variable">${git_version}</span>&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">prepare</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">${srcdir}</span>/<span class="token variable">${pkgname}</span>&quot;</span> </span><span class="code-line"> <span class="token function">git</span> checkout flow_info-3.2 </span><span class="code-line"> ./autogen.sh </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;src/lib&quot;</span> </span><span class="code-line"> <span class="token function">make</span> ndpi_network_list.c.inc </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">${srcdir}</span>/<span class="token variable">${pkgname}</span>/ndpi-netfilter&quot;</span> </span><span class="code-line"> <span class="token function">make</span> <span class="token variable assign-left">KERNEL_DIR</span><span class="token operator">=</span><span class="token string">&quot;<span class="token variable">${_kernver}</span>build&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">check</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">${srcdir}</span>/<span class="token variable">${pkgname}</span>/ndpi-netfilter&quot;</span> </span><span class="code-line"> <span class="token function">gzip</span> <span class="token variable parameter">--best</span> <span class="token variable parameter">-c</span> <span class="token string">&quot;src/xt_ndpi.ko&quot;</span> <span class="token operator">&gt;</span> <span class="token string">&quot;src/xt_ndpi.ko.gz&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">package</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">${srcdir}</span>/<span class="token variable">${pkgname}</span>/ndpi-netfilter&quot;</span> </span><span class="code-line"> <span class="token function">install</span> <span class="token variable parameter">-Dm755</span> <span class="token string">&quot;ipt/libxt_ndpi.so&quot;</span> <span class="token string">&quot;<span class="token variable">${pkgdir}</span>/usr/lib/xtables/libxt_ndpi.so&quot;</span> </span><span class="code-line"> <span class="token function">install</span> <span class="token variable parameter">-Dm644</span> <span class="token string">&quot;src/xt_ndpi.ko.gz&quot;</span> <span class="token string">&quot;<span class="token variable">${pkgdir}</span><span class="token variable">${_kernver}</span>/extra/xt_ndpi.ko.gz&quot;</span> </span><span class="code-line"> <span class="token function">install</span> <span class="token variable parameter">-Dm644</span> <span class="token string">&quot;INSTALL&quot;</span> <span class="token string">&quot;<span class="token variable">${pkgdir}</span>/usr/share/doc/<span class="token variable">${pkgname}</span>/README&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>原因出来了,这里面有:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token variable assign-left">_kernver</span><span class="token operator">=</span><span class="token string">&quot;<span class="token variable"><span class="token variable">`</span>pacman <span class="token variable parameter">-Ql</span> linux$<span class="token punctuation">{</span>_linux_custom<span class="token punctuation">}</span> <span class="token operator">|</span> <span class="token function">awk</span> <span class="token string">&#x27;/(\/modules\/)([0-9.-])+-(.*)&#x27;</span>$<span class="token punctuation">{</span>_linux_custom<span class="token punctuation">}</span><span class="token string">&#x27;\/$/ {print $2}&#x27;</span> <span class="token operator">|</span> <span class="token function">head</span> <span class="token variable parameter">-n1</span><span class="token variable">`</span></span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">install</span> <span class="token variable parameter">-Dm644</span> <span class="token string">&quot;src/xt_ndpi.ko.gz&quot;</span> <span class="token string">&quot;<span class="token variable">${pkgdir}</span><span class="token variable">${_kernver}</span>/extra/xt_ndpi.ko.gz&quot;</span> </span></code></pre></div><p>因此,在当时包构建的时候,它会取当前内核版本号,然后把 <code>xt_ndpi.ko.gz</code> install 到相应的目录, 由于 paru 并没有重建包,因此导致在新内核上安装到了错误的位置。</p><p>因此 rebuild 就可以解决问题。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">paru <span class="token variable parameter">-S</span> <span class="token variable parameter">--rebuild</span> ipt_ndpi </span></code></pre></div><hr/><p>有没有办法从程序上检测这种变动呢? 我觉得完全是可以的。简单地 list 一下这个包里面的内容,如果找到了位于 <code>usr/lib/modules/</code> 下的文件,则说明这个包是有包含内核模块的,从目录名 <code>5.12.11-arch1-1</code> 里我们完全可以提取出内核版本是 <code>5.12.11</code>, 然后再与当前运行的内核版本匹配,如果不匹配,则 paru 可以自动重建包。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">🔴 <span class="token number">2</span> ❯ <span class="token function">tar</span> <span class="token variable parameter">-tvlf</span> ipt_ndpi-1.2_3.5.0.3243.640643d9-1-any.pkg.tar.zst </span><span class="code-line">-rw-r--r-- root/root <span class="token number">45891</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 .BUILDINFO </span><span class="code-line">-rw-r--r-- root/root <span class="token number">587</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 .MTREE </span><span class="code-line">-rw-r--r-- root/root <span class="token number">339</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 .PKGINFO </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/ </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/lib/ </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/lib/modules/ </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/lib/modules/5.12.11-arch1-1/ </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/lib/modules/5.12.11-arch1-1/extra/ </span><span class="code-line">-rw-r--r-- root/root <span class="token number">3289358</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/lib/modules/5.12.11-arch1-1/extra/xt_ndpi.ko.gz </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/lib/xtables/ </span><span class="code-line">-rwxr-xr-x root/root <span class="token number">31408</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/lib/xtables/libxt_ndpi.so </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/share/ </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/share/doc/ </span><span class="code-line">drwxr-xr-x root/root <span class="token number">0</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/share/doc/ipt_ndpi/ </span><span class="code-line">-rw-r--r-- root/root <span class="token number">9812</span> <span class="token number">2021</span>-06-18 <span class="token number">23</span>:39 usr/share/doc/ipt_ndpi/README </span></code></pre></div><p>把这个解决方案向 paru 作者反馈了, 作者直接拒绝了。</p><p>可能作者觉得这不是 paru 要处理的问题,而是使用者应该处理的问题吧?</p><p>但是,人的记忆是不如电脑的,很多事情是容易忘记的。如果 paru 能自动识别需要重建不是更好?</p><p>虽然这个功能有点像“白名单”, 针对内核版本号检测了,那我是不是针对其它 lib 的版本号兼容性也要进行检测? 我觉得不尽然,能处理内核版本号的问题,不是更好?为什么支持内核检测了就一定要支持其它lib?没有哪有这个规定啊。</p><p>所以,说白了就是,这个想法,跟作者的理念是不符合的。</p><p>开源的东西,很多时候都是这样吧。是作者意愿的一种表达。这就是为什么开源容易出现很多 fork, 因为,一言不合就 fork啊,你不愿意添加,那就我自己来干喽。</p><p>当然,我目前还没有闲到这种自己去维护另一个版本的 paru 的地步。因此,先这么着吧。说不定哪天有空了,我真的 fork 了。</p> Sun, 20 Jun 2021 11:30:00 GMT ttyS3 aur-helperparuarchlinux https://ttys3.dev/blog/hugo-0-84-0-now-support-deep-merge-of-theme-params Hugo 0.84.0 Now Support Deep Merge of Theme Params https://ttys3.dev/blog/hugo-0-84-0-now-support-deep-merge-of-theme-params <h2 id="功能介绍"><a href="#功能介绍" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>功能介绍</h2><p>对于主题的 params 配置,之前版本的 Hugo 只支持浅合并(shallow merge),举例来说: 假设主题有一个配置</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">params</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">params.colours</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">blue</span><span class="token punctuation">=</span><span class="token string">&quot;#337DFF&quot;</span> </span><span class="code-line"><span class="token key property">green</span><span class="token punctuation">=</span><span class="token string">&quot;#68FF33&quot;</span> </span><span class="code-line"><span class="token key property">red</span><span class="token punctuation">=</span><span class="token string">&quot;#FF3358&quot;</span> </span></code></pre></div><p>如果是之前版本的 Hugo, 你要调整其中一个配置,比如 <code>red</code> 的颜色,你需要 copy 整个 <code>colours</code> 配置,然后把 <code>red</code> 修改成你想要的值。</p><p>现在你可以在站点配置里这样简单地进行覆盖:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">params</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">params.colours</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">red</span><span class="token punctuation">=</span><span class="token string">&quot;#fc0f03&quot;</span> </span></code></pre></div><h2 id="默认合并策略"><a href="#默认合并策略" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>默认合并策略</h2><p>参考文档 <a href="https://gohugo.io/getting-started/configuration/#merge-configuration-from-themes">https://gohugo.io/getting-started/configuration/#merge-configuration-from-themes</a></p><p>现在 <code>_merge</code> 的值可以是以下三种之一:</p><ul><li><code>none</code> 不合并</li><li><code>shallow</code> 浅copy合并 Only add values for new keys.</li><li><code>deep</code> 深度合并 Add values for new keys, merge existing.</li></ul><p>当前的默认配置是:</p><div class="relative"><pre><code class="code-highlight language-yaml"><span class="code-line"><span class="token key atrule">build</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">caches</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">frontmatter</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">imaging</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">languages</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"> <span class="token key atrule">en</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"> <span class="token key atrule">menus</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> shallow </span><span class="code-line"> <span class="token key atrule">params</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> deep </span><span class="code-line"><span class="token key atrule">markup</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">mediatypes</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> shallow </span><span class="code-line"><span class="token key atrule">menus</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> shallow </span><span class="code-line"><span class="token key atrule">minify</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">module</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">outputformats</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> shallow </span><span class="code-line"><span class="token key atrule">params</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> deep </span><span class="code-line"><span class="token key atrule">permalinks</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">related</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">sitemap</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span><span class="code-line"><span class="token key atrule">taxonomies</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token key atrule">_merge</span><span class="token punctuation">:</span> none </span></code></pre></div><h2 id="其它重要改变"><a href="#其它重要改变" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它重要改变</h2><h3 id="themes-now-support-the-config-directory"><a href="#themes-now-support-the-config-directory" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Themes now support the config directory</h3><p>Now both the project and themes/modules can store its configuration in both the top level config file (e.g. <code>config.toml</code>) or in the <code>config</code> directory. See <a href="https://gohugo.io/getting-started/configuration/#configuration-directory">Configuration Directory</a>.</p><h3 id="http-headers-in-getjsongetcsv"><a href="#http-headers-in-getjsongetcsv" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>HTTP headers in getJSON/getCSV</h3><p><code>getJSON</code> now supports custom HTTP headers. This has been a big limitation in Hugo, especially considering the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization">Authorization</a> header.</p><p>We have updated the internal Instagram shortcode to pass the access token in a header:</p><div class="relative"><pre><code class="code-highlight language-go-html-template"><span class="code-line">{{ $hideCaption := cond (eq (.Get 1) &quot;hidecaption&quot;) &quot;1&quot; &quot;0&quot; }} </span><span class="code-line">{{ $headers := dict &quot;Authorization&quot; (printf &quot;Bearer %s&quot; $accessToken) }} </span><span class="code-line">{{ with getJSON &quot;https://graph.facebook.com/v8.0/instagram_oembed/?url=https://instagram.com/p/&quot; $id &quot;/&amp;hidecaption=&quot; $hideCaption $headers }} </span><span class="code-line"> {{ .html | safeHTML }} </span><span class="code-line">{{ end }} </span></code></pre></div><p>Also see the discussion <a href="https://github.com/gohugoio/hugo/issues/7879">this issue</a> about the access token above.</p><h3 id="new-erroridf-template-func"><a href="#new-erroridf-template-func" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>New erroridf template func</h3><p>Sometime, especially when creating themes, it is useful to be able to let the user decide if an error situation is critical enough to fail the build. The new <code>erroridf</code> produces <code>ERROR</code> log statements that can be toggled off:</p><div class="relative"><pre><code class="code-highlight language-go-html-template"><span class="code-line">{{ erroridf &quot;some-custom-id&quot; &quot;Some error message.&quot; }} </span></code></pre></div><p>Will log:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">ERROR</span><span class="token operator">:</span> <span class="token maybe-class-name">Some</span> error message<span class="token punctuation">.</span> </span><span class="code-line"><span class="token property-access"><span class="token maybe-class-name">If</span></span> you feel that <span class="token keyword">this</span> should not be logged <span class="token keyword module">as</span> an <span class="token constant">ERROR</span><span class="token punctuation">,</span> you can ignore it by adding <span class="token keyword">this</span> to your site config<span class="token operator">:</span> </span><span class="code-line">ignoreErrors <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">&quot;some-custom-id&quot;</span><span class="token punctuation">]</span> </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://gohugo.io/news/0.84.0-relnotes/#deep-merge-of-theme-params">https://gohugo.io/news/0.84.0-relnotes/#deep-merge-of-theme-params</a></p><p><a href="https://github.com/gohugoio/hugo/releases/tag/v0.84.0">https://github.com/gohugoio/hugo/releases/tag/v0.84.0</a></p> Sun, 20 Jun 2021 11:08:46 GMT ttyS3 hugo https://ttys3.dev/blog/fuck-80-chars-limit Fuck 80 Chars Limit -- It is 2021 now https://ttys3.dev/blog/fuck-80-chars-limit <p>关于限制代码最大列宽:</p><p>限制在 80 个字符合适吗?</p><p>我的观点是: 都 TM 2021 年了, 80个锤子,直接来个 150 或 160 还差不多。</p><p>Linus 的观点貌似跟我一样哈?</p><blockquote><p>In case of the Linux kernel, that’s of course <strong>Linus Torvalds</strong>, who has recently shaken up the community with a mailing list response declaring an overly common, often even unwritten rule of code formatting as essentially obsolete: the 80-character line limitation. Considering the notoriety of his rants and crudeness, his response, which was initiated by a line break change in the submitted patch, seems downright diplomatic this time.</p><p><strong>Linus</strong>’ reasoning against a continuing enforcement of 80-char line limits is primarly the fact that screens are simply big enough today to comfortably fit longer lines, even with multiple terminals (or windows) next to each other. As he puts it, the only reason to stick to the limitation is using an actual VT100, which won’t serve much use in kernel development anyway.</p></blockquote><p>via <a href="https://hackaday.com/2020/06/18/ask-hackaday-are-80-characters-per-line-still-reasonable-in-2020/">https://hackaday.com/2020/06/18/ask-hackaday-are-80-characters-per-line-still-reasonable-in-2020/</a></p><p><a href="https://lkml.org/lkml/2020/5/28/1237">https://lkml.org/lkml/2020/5/28/1237</a></p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token maybe-class-name">From</span> <span class="token maybe-class-name">Linus</span> <span class="token maybe-class-name">Torvalds</span> <span class="token operator">&lt;</span><span class="token operator">&gt;</span> </span><span class="code-line"><span class="token class-name known-class-name">Date</span> <span class="token maybe-class-name">Thu</span><span class="token punctuation">,</span> <span class="token number">28</span> <span class="token maybe-class-name">May</span> <span class="token number">2020</span> <span class="token number">11</span><span class="token operator">:</span><span class="token number">43</span><span class="token operator">:</span><span class="token number">13</span> <span class="token operator">-</span><span class="token number">0700</span> </span><span class="code-line"><span class="token maybe-class-name">Subject</span> <span class="token maybe-class-name">Re</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">PATCH</span> <span class="token number">09</span><span class="token operator">/</span><span class="token number">14</span><span class="token punctuation">]</span> fs<span class="token operator">:</span> don&#x27;t change the address limit <span class="token keyword control-flow">for</span> <span class="token operator">-</span><span class="token operator">&gt;</span>write_iter <span class="token keyword">in</span> __kernel_write </span><span class="code-line">share <span class="token number">0</span> </span><span class="code-line"><span class="token maybe-class-name">On</span> <span class="token maybe-class-name">Wed</span><span class="token punctuation">,</span> <span class="token maybe-class-name">May</span> <span class="token number">27</span><span class="token punctuation">,</span> <span class="token number">2020</span> at <span class="token number">10</span><span class="token operator">:</span><span class="token number">41</span> <span class="token constant">PM</span> <span class="token maybe-class-name">Christoph</span> <span class="token maybe-class-name">Hellwig</span> <span class="token operator">&lt;</span>hch@lst<span class="token punctuation">.</span><span class="token property-access">de</span><span class="token operator">&gt;</span> wrote<span class="token operator">:</span> </span><span class="code-line"><span class="token operator">&gt;</span> </span><span class="code-line"><span class="token operator">&gt;</span> <span class="token operator">-</span>ssize_t <span class="token function">__kernel_write</span><span class="token punctuation">(</span>struct file <span class="token operator">*</span>file<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>buf<span class="token punctuation">,</span> size_t count<span class="token punctuation">,</span> loff_t <span class="token operator">*</span>pos<span class="token punctuation">)</span> </span><span class="code-line"><span class="token operator">&gt;</span> <span class="token operator">+</span>ssize_t <span class="token function">__kernel_write</span><span class="token punctuation">(</span>struct file <span class="token operator">*</span>file<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>buf<span class="token punctuation">,</span> size_t count<span class="token punctuation">,</span> </span><span class="code-line"><span class="token operator">&gt;</span> <span class="token operator">+</span> loff_t <span class="token operator">*</span>pos<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token maybe-class-name">Please</span> don&#x27;t <span class="token keyword control-flow">do</span> these kinds <span class="token keyword">of</span> pointless whitespace changes<span class="token punctuation">.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token property-access"><span class="token maybe-class-name">If</span></span> you have an actual 80x25 vt100 sitting <span class="token keyword">in</span> a corner<span class="token punctuation">,</span> it&#x27;s not really </span><span class="code-line">conducive to kernel development any more<span class="token punctuation">.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token property-access"><span class="token maybe-class-name">Yes</span></span><span class="token punctuation">,</span> yes<span class="token punctuation">,</span> we<span class="token string">&#x27;d like to have shorter lines for new code, but no, don&#x27;</span>t </span><span class="code-line"><span class="token keyword control-flow">do</span> silly line breaks that just makes old code look and grep worse<span class="token punctuation">.</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token property-access"><span class="token maybe-class-name">Linus</span></span> </span></code></pre></div><p><a href="https://lkml.org/lkml/2020/5/29/1038">https://lkml.org/lkml/2020/5/29/1038</a></p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token maybe-class-name">From</span> <span class="token maybe-class-name">Linus</span> <span class="token maybe-class-name">Torvalds</span> <span class="token operator">&lt;</span><span class="token operator">&gt;</span> </span><span class="code-line"><span class="token class-name known-class-name">Date</span> <span class="token maybe-class-name">Fri</span><span class="token punctuation">,</span> <span class="token number">29</span> <span class="token maybe-class-name">May</span> <span class="token number">2020</span> <span class="token number">12</span><span class="token operator">:</span><span class="token number">19</span><span class="token operator">:</span><span class="token number">02</span> <span class="token operator">-</span><span class="token number">0700</span> </span><span class="code-line"><span class="token maybe-class-name">Subject</span> <span class="token maybe-class-name">Re</span><span class="token operator">:</span> clean up kernel_<span class="token punctuation">{</span>read<span class="token punctuation">,</span>write<span class="token punctuation">}</span> <span class="token operator">&amp;</span> friends v2 </span><span class="code-line">share 4k </span><span class="code-line"><span class="token maybe-class-name">On</span> <span class="token maybe-class-name">Fri</span><span class="token punctuation">,</span> <span class="token maybe-class-name">May</span> <span class="token number">29</span><span class="token punctuation">,</span> <span class="token number">2020</span> at <span class="token number">6</span><span class="token operator">:</span><span class="token number">08</span> <span class="token constant">AM</span> <span class="token maybe-class-name">David</span> <span class="token maybe-class-name">Laight</span> <span class="token operator">&lt;</span><span class="token maybe-class-name">David</span><span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">Laight</span></span>@aculab<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">&gt;</span> wrote<span class="token operator">:</span> </span><span class="code-line"><span class="token operator">&gt;</span> </span><span class="code-line"><span class="token operator">&gt;</span> <span class="token constant">A</span> wide monitor is <span class="token keyword control-flow">for</span> looking at lots <span class="token keyword">of</span> files<span class="token punctuation">.</span> </span></code></pre></div><blockquote><p>Not necessarily.</p><p><strong>Excessive line breaks are BAD. They cause real and every-day problems.</strong></p><p>They cause problems for things like &quot;grep&quot; both in the patterns and in the output, since grep (and a lot of other very basic unix utilities) is fundamentally line-based.</p><p>So the fact is, many of us have long long since skipped the whole &quot;80-column terminal&quot; model, for the same reason that we have many more lines than 25 lines visible at a time.</p><p>And honestly, I don&#x27;t want to see patches that make the kernel reading experience worse for me and likely for the vast majority of people, based on the argument that some odd people have small terminal windows.</p><p><strong>If you or Christoph have 80 character lines, you&#x27;ll get possibly ugly wrapped output. Tough. That&#x27;s <em>your</em> choice. Your hardware limitations shouldn&#x27;t be a pain for the rest of us.</strong></p><p>Longer lines are fundamentally useful. My monitor is not only a lot wider than it is tall, my fonts are universally narrower than they are tall. Long lines are natural.</p><p>When I tile my terminal windows on my display, I can have 6 terminals visible at one time, and that&#x27;s because I have them three wide. And I could still fit 80% of a fourth one side-by-side.</p><p>And guess what? That&#x27;s with my default &quot;100x50&quot; terminal window (go to your gnome terminal settings, you&#x27;ll find that the 80x25 thing is just an initial default that you can change), not with some 80x25 one. And that&#x27;s with a font that has anti-aliasing and isn&#x27;t some pixelated mess.</p><p>And most of my terminals actually end up being dragged wider and taller than that. I checked, and my main one is 142x76 characters right now, because it turns out that wider (and taller) terminals are useful not just for source code.</p><p><strong>Have you looked at &quot;ps ax&quot; output lately? Or used &quot;top&quot;? Or done &quot;git diff --stat&quot; or any number of things where it turns out that 80x25 is really really limiting, and is simply NO LONGER RELEVANT to most of us.</strong></p><p><strong>So no. I do not care about somebody with a 80x25 terminal window getting line wrapping.</strong></p><p>For exactly the same reason I find it completely irrelevant if somebody says that their kernel compile takes 10 hours because they are doing kernel development on a Raspberry PI with 4GB of RAM.</p><p>People with restrictive hardware shouldn&#x27;t make it more inconvenient for people who have better resources. Yes, we&#x27;ll accommodate things to within reasonable limits. But no, 80-column terminals in 2020 isn&#x27;t &quot;reasonable&quot; any more as far as I&#x27;m concerned. People commonly used 132-column terminals even back in the 80&#x27;s, for chrissake, don&#x27;t try to make 80 columns some immovable standard.</p><p><strong>If you choose to use a 80-column terminal, you can live with the line wrapping. It&#x27;s just that simple.</strong></p><p>And longer lines are simply useful. Part of that is that we aren&#x27;t programming in the 80&#x27;s any more, and our source code is fundamentally wider as a result.</p><p>Yes, local iteration variables are still called &#x27;i&#x27;, because more context just isn&#x27;t helpful for some anonymous counter. Being concise is still a good thing, and overly verbose names are not inherently better.</p><p>But still - it&#x27;s entirely reasonable to have variable names that are 10-15 characters and it makes the code more legible. Writing things out instead of using abbreviations etc.</p><p>And yes, we do use wide tabs, because that makes indentation something you can visually see in the structure at a glance and on a whole-function basis, rather than something you have to try to visually &quot;line up&quot; things for or count spaces.</p><p>So we have lots of fairly fundamental issues that fairly easily make for longer lines in many circumstances.</p><p>And yes, we do line breaks at some point. But there really isn&#x27;t any reason to make that point be 80 columns any more.</p></blockquote><blockquote><p>------------ Linus</p></blockquote> Sun, 06 Jun 2021 16:27:35 GMT ttyS3 coding-style80charslimitfuck https://ttys3.dev/blog/staticcheck-the-most-confusing-linter-in-golangci-lint staticcheck -- golangci-lint 中最令人困惑的一个 linter https://ttys3.dev/blog/staticcheck-the-most-confusing-linter-in-golangci-lint <p>如果你不想看过程,那就直接跳到最后看一句话总结吧。</p><h2 id="megacheck"><a href="#megacheck" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>megacheck</h2><p><code>megacheck</code> 其实是一个 <code>deprecated</code> linter, 不过只是被原作者deprecated, 目前 golangci-lint 并没有 deprecated 它。原因主要是向后兼容性 (see <a href="https://github.com/golangci/golangci-lint/issues/357">https://github.com/golangci/golangci-lint/issues/357</a> )。</p><p>这可能是最令人费解的一个linter了,为什么呢?我这里简单总结一下:</p><p>megacheck 是 <a href="https://github.com/dominikh/go-tools">https://github.com/dominikh/go-tools</a> 早期代码里的一个linter, 它包含了3个linter: gosimple staticcheck unused 而 go-tools 的 go module 名称为: <code>honnef.co/go/tools</code>, 没错,并不是 <code>github.com/dominikh/go-tools</code> 到这里还没结束,嗯。 新版本的go-tools 代码里已经没有 megacheck 这个 linter了。 新版本取了一个新名字叫 <a href="https://staticcheck.io/">Staticcheck</a> , 自称 &quot;The advanced Go linter&quot;, 自我描述为 &quot;The best static analysis for Go that money can&#x27;t buy&quot; 代码仓库地址保持不变, 还在 <a href="https://github.com/dominikh/go-tools">https://github.com/dominikh/go-tools</a> 不单有自己的官网,而且把它所有的检测文档化了, 访问 <a href="https://staticcheck.io/docs/checks">https://staticcheck.io/docs/checks</a> 可以查看所有检测.</p><p>早期的 <code>go-tools</code> (也就是现在的 <code>staticcheck</code>) 其实是包含一系列linter的, <code>gosimple</code> <code>staticcheck</code> <code>unused</code> 其中 <code>staticcheck 里面包含了 </code>stylecheck`.</p><p>而新版本 的 <code>staticcheck</code> (这里指的是 cmd, 不是staticcheck package <code>&quot;honnef.co/go/tools/staticcheck&quot;</code>)</p><p>包含了4种linter:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line">gosimple <span class="token string">&quot;honnef.co/go/tools/simple&quot;</span> </span><span class="code-line">staticcheck <span class="token string">&quot;honnef.co/go/tools/staticcheck&quot;</span> </span><span class="code-line">stylecheck <span class="token string">&quot;honnef.co/go/tools/stylecheck&quot;</span> </span><span class="code-line">unused <span class="token string">&quot;honnef.co/go/tools/unused&quot;</span> </span></code></pre></div><p>see <a href="https://github.com/dominikh/go-tools/blob/master/cmd/staticcheck/staticcheck.go">https://github.com/dominikh/go-tools/blob/master/cmd/staticcheck/staticcheck.go</a></p><p>而 当前版本的 <code>golangci-lint</code> (现在最新是 v1.40.1 ) 里的 <code>staticcheck</code> 实际上指的是 <code>&quot;honnef.co/go/tools/staticcheck&quot;</code>, 并不是指 <a href="https://github.com/dominikh/go-tools/blob/master/cmd/staticcheck/staticcheck.go">https://github.com/dominikh/go-tools/blob/master/cmd/staticcheck/staticcheck.go</a></p><p><a href="https://github.com/golangci/golangci-lint/issues/357">https://github.com/golangci/golangci-lint/issues/357</a> 说的 <code>staticcheck</code> 是指 cmd/staticcheck, 也就是真正的 四合一版的 staticcheck</p><p>但是由于 当前旧版本的 staticcheck 是在 golangci-lint 的 <a href="https://golangci-lint.run/usage/linters/#enabled-by-default-linters">&quot;Enabled By Default Linters&quot;</a> 里,基于 semver, 这个提议只能放在 v2.0.0 版的 golangci-lint, see <a href="https://github.com/golangci/golangci-lint/issues/357#issuecomment-841850534">https://github.com/golangci/golangci-lint/issues/357#issuecomment-841850534</a></p><blockquote><p>staticcheck is up-to-date in golangci-lint, and we update the dependency automatically via dependabot.</p></blockquote><blockquote><p>The issue is still opened because the merge of the 4 linters is breaking, so it will be done in the next major version (v2).</p></blockquote><p>再回到 staticcheck, 为什么仓库名这么奇怪,还是叫 <code>go-tools</code> 呢?一来,可能是由于历史原因,作者保留了仓库名称没有变。 二来,其实 go-tools 下确实不只 staticcheck 这个 linter, 还有另一个小工具 <code>keyify</code> 和 <code>structlayout</code> 三兄弟</p><p>注意, golangci-lint 虽然 fork 并保留了 go-tools 早期的代码,但是现在最新发布的 golangci-lint 其实是直接引用了最新的 go-tools 包代码.</p><p>如果我们将配置设置为禁用所有linter(主要是默认启用的那些), 再执行 <code>golangci-lint run -v</code>:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">linters</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">disable-all</span> <span class="token punctuation">=</span> <span class="token boolean">true</span> </span><span class="code-line"><span class="token key property">enable</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&quot;megacheck&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">]</span> </span></code></pre></div><p>会发现如下提示:</p><blockquote><p>INFO [lintersdb] Active 3 linters: [gosimple staticcheck unused]</p></blockquote><p>我们看看 golangci-lint 的代码就明白为什么启用 megacheck 后会提示我们启用了3个 linter:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// file: pkg/lint/lintersdb/manager.go</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// https://github.com/golangci/golangci-lint/blob/fe0db3db215535884342b3b884ec0e637314921d/pkg/lint/lintersdb/manager.go#L144</span> </span><span class="code-line"><span class="token keyword">const</span> megacheckName <span class="token operator">=</span> <span class="token string">&quot;megacheck&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// https://github.com/golangci/golangci-lint/blob/fe0db3db215535884342b3b884ec0e637314921d/pkg/lint/lintersdb/manager.go#L180</span> </span><span class="code-line"> </span><span class="code-line">linter<span class="token punctuation">.</span><span class="token function">NewConfig</span><span class="token punctuation">(</span>golinters<span class="token punctuation">.</span><span class="token function">NewStaticcheck</span><span class="token punctuation">(</span>staticcheckCfg<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithSince</span><span class="token punctuation">(</span><span class="token string">&quot;v1.0.0&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithLoadForGoAnalysis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithPresets</span><span class="token punctuation">(</span>linter<span class="token punctuation">.</span>PresetBugs<span class="token punctuation">,</span> linter<span class="token punctuation">.</span>PresetMetaLinter<span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithAlternativeNames</span><span class="token punctuation">(</span>megacheckName<span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithURL</span><span class="token punctuation">(</span><span class="token string">&quot;https://staticcheck.io/&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line">linter<span class="token punctuation">.</span><span class="token function">NewConfig</span><span class="token punctuation">(</span>golinters<span class="token punctuation">.</span><span class="token function">NewUnused</span><span class="token punctuation">(</span>unusedCfg<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithSince</span><span class="token punctuation">(</span><span class="token string">&quot;v1.20.0&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithLoadForGoAnalysis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithPresets</span><span class="token punctuation">(</span>linter<span class="token punctuation">.</span>PresetUnused<span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithAlternativeNames</span><span class="token punctuation">(</span>megacheckName<span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">ConsiderSlow</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithChangeTypes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithURL</span><span class="token punctuation">(</span><span class="token string">&quot;https://github.com/dominikh/go-tools/tree/master/unused&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line">linter<span class="token punctuation">.</span><span class="token function">NewConfig</span><span class="token punctuation">(</span>golinters<span class="token punctuation">.</span><span class="token function">NewGosimple</span><span class="token punctuation">(</span>gosimpleCfg<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithSince</span><span class="token punctuation">(</span><span class="token string">&quot;v1.20.0&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithLoadForGoAnalysis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithPresets</span><span class="token punctuation">(</span>linter<span class="token punctuation">.</span>PresetStyle<span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithAlternativeNames</span><span class="token punctuation">(</span>megacheckName<span class="token punctuation">)</span><span class="token punctuation">.</span> </span><span class="code-line"> <span class="token function">WithURL</span><span class="token punctuation">(</span><span class="token string">&quot;https://github.com/dominikh/go-tools/tree/master/simple&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> </span></code></pre></div><h2 id="staticcheck"><a href="#staticcheck" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>staticcheck</h2><p>当然,如果你想安装原汁原味的 staticcheck, 也不是不可以:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">go <span class="token function">install</span> honnef.co/go/tools/cmd/staticcheck@latest </span></code></pre></div><p><code>staticcheck -list-checks</code> 可以列出它当前支持的所有检测</p><p>当前最新稳定版为 <a href="https://github.com/dominikh/go-tools/releases/tag/v0.2.0">v0.2.0</a></p><p>STATICCHECK 2021.1 RELEASE NOTES <a href="https://staticcheck.io/changes/2021.1">https://staticcheck.io/changes/2021.1</a></p><p>新增加了啥和改了啥,我这里就不说了,大家自己看文档, 我挑两个个人比较关注的说一下:</p><h3 id="better-integration-with-gopls"><a href="#better-integration-with-gopls" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Better integration with gopls</h3><p>Several behind the scenes changes prepare this release for better integration with gopls. This will include more accurate severities for diagnostics as well as numerous new refactorings. These improvements will be part of a future gopls release.</p><p><a href="https://github.com/golang/tools/blob/master/gopls/doc/settings.md#staticcheck-bool">https://github.com/golang/tools/blob/master/gopls/doc/settings.md#staticcheck-bool</a></p><h3 id="deletion-of-rdeps"><a href="#deletion-of-rdeps" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Deletion of rdeps</h3><p>The rdeps tool has been deleted. This was a GOPATH-centric tool that allowed finding all reverse dependencies of a Go package. Both the move to Go modules as well as the emergence of much better tooling for inspecting dependencies (such as <a href="https://github.com/loov/goda">goda</a>) has made rdeps redundant.</p><p>不得不说一下,作者这里推荐的 <a href="https://github.com/loov/goda">goda</a> 也是个好东西。 配合 dot (来自Linux graphviz包) 可以画出漂亮的mod依赖图来:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">git</span> clone https://github.com/loov/goda <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">cd</span> goda </span><span class="code-line">goda graph github.com/loov/goda/<span class="token punctuation">..</span>. <span class="token operator">|</span> dot <span class="token parameter variable">-Tsvg</span> <span class="token parameter variable">-o</span> graph.svg </span></code></pre></div><p>我们看看 <a href="https://github.com/golangci/go-tools/blob/master/cmd/megacheck/megacheck.go">https://github.com/golangci/go-tools/blob/master/cmd/megacheck/megacheck.go</a> 其导入的关键package为:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"> <span class="token string">&quot;github.com/golangci/go-tools/simple&quot;</span> </span><span class="code-line"> <span class="token string">&quot;github.com/golangci/go-tools/staticcheck&quot;</span> </span><span class="code-line"> <span class="token string">&quot;github.com/golangci/go-tools/unused&quot;</span> </span></code></pre></div><p><a href="https://github.com/golangci/go-tools/blob/master/cmd/staticcheck/staticcheck.go">https://github.com/golangci/go-tools/blob/master/cmd/staticcheck/staticcheck.go</a> 导入的</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"> <span class="token string">&quot;github.com/golangci/go-tools/simple&quot;</span> </span><span class="code-line"> <span class="token string">&quot;github.com/golangci/go-tools/staticcheck&quot;</span> </span><span class="code-line"> <span class="token string">&quot;github.com/golangci/go-tools/stylecheck&quot;</span> </span><span class="code-line"> <span class="token string">&quot;github.com/golangci/go-tools/unused&quot;</span> </span></code></pre></div><p>然后我们继续看 <a href="https://github.com/golangci/go-tools/tree/master/cmd">https://github.com/golangci/go-tools/tree/master/cmd</a> 就发现, 早期的go-tools(也就是现在的staticcheck) 其实包含一系列的linter:</p><ol><li>errcheck-ng - errcheck-ng is the next generation of errcheck.</li><li>gosimple</li><li>keyify</li><li>megacheck</li><li>rdeps</li><li>staticcheck</li><li>structlayout-optimize</li><li>structlayout-pretty</li><li>structlayout</li><li>unused</li></ol><p>在 golangci-lint 当前版本 (v1.40.1)里, <code>megacheck = [gosimple staticcheck unused]</code></p><p>staticcheck 就只有 staticcheck</p><p>我们看看新版本的: <a href="https://github.com/dominikh/go-tools/tree/master/cmd">https://github.com/dominikh/go-tools/tree/master/cmd</a> 只剩下</p><ol><li>keyify</li><li>staticcheck</li><li>structlayout-optimize</li><li>structlayout-pretty</li><li>structlayout</li></ol><p>Keyify turns unkeyed struct literals <code>(T{1, 2, 3})</code> into keyed ones <code>(T{A: 1, B: 2, C: 3})</code></p><p>rdeps scans GOPATH for all reverse dependencies of a set of Go packages.</p><p>staticcheck offers extensive analysis of Go code, covering a myriad of categories. It will detect bugs, suggest code simplifications, point out dead code, and more.</p><p>由于 go module 的引入, 已经不存在全局唯一的 GOPATH 了, 因此 rdeps 也在<a href="https://github.com/dominikh/go-tools/commit/b5c3c3362d4eacd4647a452510bc7889d6ced208">最近被作者移除</a></p><p>cmd/rdeps: delete rdeps The move to Go modules has greatly diminished the usefulness of the rdeps tool, as there is no longer a universe of packages (GOPATH) to inspect, and because we&#x27;ve never updated the tool to work with modules in the first place.</p><p>On top of that, a much more powerful tool – goda – has emerged, which allows for far more advanced queries on dependency graphs in the scope of a module.</p><p><a href="https://github.com/dominikh/go-tools/blob/master/cmd/structlayout/README.md">https://github.com/dominikh/go-tools/blob/master/cmd/structlayout/README.md</a></p><p>The structlayout utility prints the layout of a struct – that is the byte offset and size of each field, respecting alignment/padding.</p><p>The information is printed in human-readable form by default, but can be emitted as JSON with the -json flag. This makes it easy to consume this information in other tools.</p><p>A utility called structlayout-pretty takes this JSON and prints an ASCII graphic representing the memory layout.</p><p>structlayout-optimize is another tool. Inspired by maligned, it reads structlayout JSON on stdin and reorders fields to minimize the amount of padding. The tool can itself emit JSON and feed into e.g. structlayout-pretty.</p><p>structlayout-svg is a third-party tool that, similarly to structlayout-pretty, visualises struct layouts. It does so by generating a fancy-looking SVG graphic. You can install it via</p><p><code>go get github.com/ajstarks/svgo/structlayout-svg</code></p><p>那么,为什么我们默认没有启用 stylecheck 呢? 因为这个 linter 实在是太难过了,尤其是对于历史悠久的代码。 我这里随便跑一个开了 stylecheck 的,列举一些例子哈:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> <span class="token keyword">var</span> theSql should be <span class="token function">theSQL</span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> struct field <span class="token maybe-class-name">UserId</span> should be <span class="token function"><span class="token maybe-class-name">UserID</span></span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> struct field <span class="token maybe-class-name">HttpServer</span> should be <span class="token function"><span class="token maybe-class-name">HTTPServer</span></span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> struct field <span class="token maybe-class-name">BaseUserApi</span> should be <span class="token function"><span class="token maybe-class-name">BaseUserAPI</span></span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> <span class="token keyword">var</span> searchDb should be <span class="token function">searchDB</span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> <span class="token keyword">var</span> infoJson should be <span class="token function">infoJSON</span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> method parameter userId should be <span class="token function">userID</span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> method parameter reqUid should be <span class="token function">reqUID</span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> </span><span class="code-line"><span class="token constant">ST1003</span><span class="token operator">:</span> should not use <span class="token constant">ALL_CAPS</span> <span class="token keyword">in</span> <span class="token maybe-class-name">Go</span> names<span class="token punctuation">;</span> use <span class="token maybe-class-name">CamelCase</span> <span class="token function">instead</span> <span class="token punctuation">(</span>stylecheck<span class="token punctuation">)</span> <span class="token comment">// const PROM_SUBSYSTEM = &quot;user_search_updater&quot;</span> </span></code></pre></div><p>但是,如果我们直接运行 <code>staticcheck ./...</code> 却不会有这个错误。这是为什么?</p><p>我们看看 golangci-lint 的代码:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// pkg/golinters/staticcheck_common.go</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">staticCheckConfig</span><span class="token punctuation">(</span>settings <span class="token operator">*</span>config<span class="token punctuation">.</span>StaticCheckSettings<span class="token punctuation">)</span> <span class="token operator">*</span>scconfig<span class="token punctuation">.</span>Config <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">var</span> cfg <span class="token operator">*</span>scconfig<span class="token punctuation">.</span>Config </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> settings <span class="token operator">==</span> <span class="token boolean">nil</span> <span class="token operator">||</span> <span class="token operator">!</span>settings<span class="token punctuation">.</span><span class="token function">HasConfiguration</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token operator">&amp;</span>scconfig<span class="token punctuation">.</span>Config<span class="token punctuation">{</span> </span><span class="code-line"> Checks<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">&quot;*&quot;</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// override for compatibility reason. Must drop in the next major version.</span> </span><span class="code-line"> Initialisms<span class="token punctuation">:</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>Initialisms<span class="token punctuation">,</span> </span><span class="code-line"> DotImportWhitelist<span class="token punctuation">:</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>DotImportWhitelist<span class="token punctuation">,</span> </span><span class="code-line"> HTTPStatusCodeWhitelist<span class="token punctuation">:</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>HTTPStatusCodeWhitelist<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> cfg <span class="token operator">=</span> <span class="token operator">&amp;</span>scconfig<span class="token punctuation">.</span>Config<span class="token punctuation">{</span> </span><span class="code-line"> Checks<span class="token punctuation">:</span> settings<span class="token punctuation">.</span>Checks<span class="token punctuation">,</span> </span><span class="code-line"> Initialisms<span class="token punctuation">:</span> settings<span class="token punctuation">.</span>Initialisms<span class="token punctuation">,</span> </span><span class="code-line"> DotImportWhitelist<span class="token punctuation">:</span> settings<span class="token punctuation">.</span>DotImportWhitelist<span class="token punctuation">,</span> </span><span class="code-line"> HTTPStatusCodeWhitelist<span class="token punctuation">:</span> settings<span class="token punctuation">.</span>HTTPStatusCodeWhitelist<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>Checks<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> cfg<span class="token punctuation">.</span>Checks <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>Checks<span class="token punctuation">,</span> <span class="token string">&quot;*&quot;</span><span class="token punctuation">)</span> <span class="token comment">// override for compatibility reason. Must drop in the next major version.</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>Initialisms<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> cfg<span class="token punctuation">.</span>Initialisms <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>Initialisms<span class="token punctuation">,</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>Initialisms<span class="token operator">...</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>DotImportWhitelist<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> cfg<span class="token punctuation">.</span>DotImportWhitelist <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>DotImportWhitelist<span class="token punctuation">,</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>DotImportWhitelist<span class="token operator">...</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>HTTPStatusCodeWhitelist<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> cfg<span class="token punctuation">.</span>HTTPStatusCodeWhitelist <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>HTTPStatusCodeWhitelist<span class="token punctuation">,</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>HTTPStatusCodeWhitelist<span class="token operator">...</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> cfg<span class="token punctuation">.</span>Checks <span class="token operator">=</span> <span class="token function">normalizeList</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>Checks<span class="token punctuation">)</span> </span><span class="code-line"> cfg<span class="token punctuation">.</span>Initialisms <span class="token operator">=</span> <span class="token function">normalizeList</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>Initialisms<span class="token punctuation">)</span> </span><span class="code-line"> cfg<span class="token punctuation">.</span>DotImportWhitelist <span class="token operator">=</span> <span class="token function">normalizeList</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>DotImportWhitelist<span class="token punctuation">)</span> </span><span class="code-line"> cfg<span class="token punctuation">.</span>HTTPStatusCodeWhitelist <span class="token operator">=</span> <span class="token function">normalizeList</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>HTTPStatusCodeWhitelist<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">return</span> cfg </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span></code></pre></div><p>由于当前版本的 golangci-lint 将 staticcheck 一分为四了,因此 这个 <code>staticCheckConfig</code> 实际上是给四个 linter 共用的获取配置的方法.</p><p>在 golangci-lint 中,对于 staticcheck 4件套, 默认情况下,我们没有做任何配置, 因此是执行的:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"> <span class="token keyword">if</span> settings <span class="token operator">==</span> <span class="token boolean">nil</span> <span class="token operator">||</span> <span class="token operator">!</span>settings<span class="token punctuation">.</span><span class="token function">HasConfiguration</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token operator">&amp;</span>scconfig<span class="token punctuation">.</span>Config<span class="token punctuation">{</span> </span><span class="code-line"> Checks<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">&quot;*&quot;</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// override for compatibility reason. Must drop in the next major version.</span> </span><span class="code-line"> Initialisms<span class="token punctuation">:</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>Initialisms<span class="token punctuation">,</span> </span><span class="code-line"> DotImportWhitelist<span class="token punctuation">:</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>DotImportWhitelist<span class="token punctuation">,</span> </span><span class="code-line"> HTTPStatusCodeWhitelist<span class="token punctuation">:</span> scconfig<span class="token punctuation">.</span>DefaultConfig<span class="token punctuation">.</span>HTTPStatusCodeWhitelist<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>我们看一下 <code>HasConfiguration()</code> 方法:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"> </span><span class="code-line"><span class="token comment">// pkg/config/linters_settings.go</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">type</span> StaticCheckSettings <span class="token keyword">struct</span> <span class="token punctuation">{</span> </span><span class="code-line"> GoVersion <span class="token builtin">string</span> <span class="token string">`mapstructure:&quot;go&quot;`</span> </span><span class="code-line"> </span><span class="code-line"> Checks <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span> <span class="token string">`mapstructure:&quot;checks&quot;`</span> </span><span class="code-line"> Initialisms <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span> <span class="token string">`mapstructure:&quot;initialisms&quot;`</span> <span class="token comment">// only for stylecheck</span> </span><span class="code-line"> DotImportWhitelist <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span> <span class="token string">`mapstructure:&quot;dot-import-whitelist&quot;`</span> <span class="token comment">// only for stylecheck</span> </span><span class="code-line"> HTTPStatusCodeWhitelist <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span> <span class="token string">`mapstructure:&quot;http-status-code-whitelist&quot;`</span> <span class="token comment">// only for stylecheck</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// pkg/config/linters_settings.go</span> </span><span class="code-line"><span class="token keyword">func</span> <span class="token punctuation">(</span>s <span class="token operator">*</span>StaticCheckSettings<span class="token punctuation">)</span> <span class="token function">HasConfiguration</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">bool</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token function">len</span><span class="token punctuation">(</span>s<span class="token punctuation">.</span>Initialisms<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">||</span> <span class="token function">len</span><span class="token punctuation">(</span>s<span class="token punctuation">.</span>HTTPStatusCodeWhitelist<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">||</span> <span class="token function">len</span><span class="token punctuation">(</span>s<span class="token punctuation">.</span>DotImportWhitelist<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">||</span> <span class="token function">len</span><span class="token punctuation">(</span>s<span class="token punctuation">.</span>Checks<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>除了注意 <code>HasConfiguration()</code>, 我们还需要注意这里的 <code>only for stylecheck</code>, 即 initialisms dot-import-whitelist 和 http-status-code-whitelist 这3个配置都是仅对 stylecheck 生效的。</p><p>通过查看 <code>HasConfiguration()</code> 的代码,我们清楚了,只要 checks initialisms dot-import-whitelist http-status-code-whitelist 四个配置里的任何一个存在,就会先应用用户的配置。</p><p>另外, <code>func staticCheckConfig</code> 里面还有逻辑,即 initialisms dot-import-whitelist http-status-code-whitelist 任何一个为空,都会取 &quot;honnef.co/go/tools/config&quot; 的默认配置, 也就是</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// https://github.com/dominikh/go-tools/blob/e75722ce7c1c555645e84dc08b2b9e8d54624d98/config/config.go#L159</span> </span><span class="code-line"><span class="token keyword">var</span> DefaultConfig <span class="token operator">=</span> Config<span class="token punctuation">{</span> </span><span class="code-line"> Checks<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">&quot;all&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1000&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1003&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1016&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1020&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1021&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1022&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1023&quot;</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> Initialisms<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;ACL&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;API&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;ASCII&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;CPU&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;CSS&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;DNS&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;EOF&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;GUID&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;HTML&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;HTTP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;HTTPS&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;ID&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;IP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;JSON&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;QPS&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;RAM&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;RPC&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;SLA&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;SMTP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;SQL&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;SSH&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;TCP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;TLS&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;TTL&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;UDP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;UI&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;GID&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;UID&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;UUID&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;URI&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;URL&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;UTF8&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;VM&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;XML&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;XMPP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;XSRF&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;XSS&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;SIP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;RTP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;AMQP&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;DB&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;TS&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> DotImportWhitelist<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> HTTPStatusCodeWhitelist<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">&quot;200&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;400&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;404&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;500&quot;</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>蛋疼的地方来了, golangci-lint 为了兼容性, 只要发现 <code>checks</code> 为空, 就会将 <code>checks</code> 设置成 <code>*</code> ,注意这个 <code>*</code>, 并 <strong>不是</strong> 新版本的 staticcheck (这里指的是cmd, 不是package) 的默认值。</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// pkg/golinters/staticcheck_common.go func staticCheckConfig</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>Checks<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> </span><span class="code-line"> cfg<span class="token punctuation">.</span>Checks <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>cfg<span class="token punctuation">.</span>Checks<span class="token punctuation">,</span> <span class="token string">&quot;*&quot;</span><span class="token punctuation">)</span> <span class="token comment">// override for compatibility reason. Must drop in the next major version.</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>没错, staticcheck 的默认配置是符合大多数人习惯的, 但是 golangci-lint 基于兼容性考虑,无法应用默认配置</p><blockquote><p>override for compatibility reason. Must drop in the next major version.</p></blockquote><p>所以,作为使用者,符合习惯的做法应该是, 按 staticcheck 的默认配置,根据自己的需求自行调整。 当然,如果不调整,最简单的就是取 staticcheck 的默认配置了。</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">linters-settings.stylecheck</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">checks</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">&quot;all&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1000&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1003&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1016&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1020&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1021&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1022&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;-ST1023&quot;</span> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">dot-import-whitelist</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">http-status-code-whitelist</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> </span></code></pre></div><p>但是,这个配置在最新稳定版的 1.40.1 golangci-lint 并不生效,原因是,我们看的代码是 master 分支的。</p><p>1.40.1 golangci-lint 引用的是 <code>honnef.co/go/tools v0.1.4</code> 实际上是已经支持 <code>checks</code> 选项的,但是 golangci-lint 的代码没有加。</p><p>最初 4 兄弟在 golangci-lint 只有一个 go 版本的配置项,还是这个 PR 引入的: <a href="https://github.com/golangci/golangci-lint/pull/1946/files">https://github.com/golangci/golangci-lint/pull/1946/files</a></p><p>直到这个 PR <a href="https://github.com/golangci/golangci-lint/pull/2017">https://github.com/golangci/golangci-lint/pull/2017</a></p><p>ldez committed 4 days ago (当前写作日期: 2021-06-01)</p><p>对应的提交 <a href="https://github.com/golangci/golangci-lint/commit/b916c9318bf31c6dca73e64c1751bd62a661e2bb">https://github.com/golangci/golangci-lint/commit/b916c9318bf31c6dca73e64c1751bd62a661e2bb</a></p><p>这个 PR 同时还用一句话讲清楚了 golangci-lint 官方一直不愿意讲的事情:</p><blockquote><p>Staticcheck is split into 4 linters in golangci-lint staticcheck, gosimple, stylecheck and unused.</p></blockquote><p>相关问题: <a href="https://github.com/golangci/golangci-lint/discussions/1989#discussioncomment-745004">https://github.com/golangci/golangci-lint/discussions/1989#discussioncomment-745004</a></p><blockquote><p>If do so, why it is there 4 times?</p></blockquote><p>staticcheck is a binary and a set of rules, those rules are grouped in &quot;category&quot;: <code>staticcheck</code>, <code>gosimple</code>, <code>stylecheck</code> and <code>unused</code>.</p><ul><li>staticcheck: <a href="https://github.com/dominikh/go-tools/blob/331bcca40621580531c9b8a9cb7d5c2c06c709d2/staticcheck/analysis.go#L23">https://github.com/dominikh/go-tools/blob/331bcca40621580531c9b8a9cb7d5c2c06c709d2/staticcheck/analysis.go#L23</a></li><li>stylecheck: <a href="https://github.com/dominikh/go-tools/blob/331bcca40621580531c9b8a9cb7d5c2c06c709d2/stylecheck/analysis.go#L14">https://github.com/dominikh/go-tools/blob/331bcca40621580531c9b8a9cb7d5c2c06c709d2/stylecheck/analysis.go#L14</a></li><li>simple: <a href="https://github.com/dominikh/go-tools/blob/331bcca40621580531c9b8a9cb7d5c2c06c709d2/simple/analysis.go#L11">https://github.com/dominikh/go-tools/blob/331bcca40621580531c9b8a9cb7d5c2c06c709d2/simple/analysis.go#L11</a></li><li>unused: <a href="https://github.com/dominikh/go-tools/blob/331bcca40621580531c9b8a9cb7d5c2c06c709d2/unused/unused.go#L418">https://github.com/dominikh/go-tools/blob/331bcca40621580531c9b8a9cb7d5c2c06c709d2/unused/unused.go#L418</a></li></ul><p>megacheck was the first name of staticcheck, the &quot;categories&quot; were binaries, and as you can understand there are historical reasons behind those &quot;linters&quot; inside golangci-lint.</p><p>More information about the 4 linters: <a href="https://github.com/golangci/golangci-lint/issues/357">https://github.com/golangci/golangci-lint/issues/357</a></p><hr/><blockquote><p>And why actually the staticcheck config file staticcheck.conf is ignored when running with golangci-lint?</p></blockquote><p>The file is partially ignored: you can use <code>staticcheck.conf</code> to define <code>initialisms</code>, <code>dot_import_whitelist</code>, <code>http_status_code_whitelist</code> but <code>checks</code> are ignored (instead you have to use <code>issues.excludes</code> in the golanci-lint configuration).</p><p>It is mainly related to the API of staticcheck: we don&#x27;t have access to the element to handle the staticcheck configuration.</p><p>About the configuration, you can follow <a href="https://github.com/golangci/golangci-lint/issues/1275">https://github.com/golangci/golangci-lint/issues/1275</a></p><p>新版本的 golangci-lint 里面有这么个方法(实际上基本上是copy自dominikh/go-tools的):</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"> </span><span class="code-line"><span class="token comment">// https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/lintcmd/lint.go#L437-L477</span> </span><span class="code-line"><span class="token comment">// nolint // Keep the original source code.</span> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">filterAnalyzerNames</span><span class="token punctuation">(</span>analyzers <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">,</span> checks <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token builtin">bool</span> <span class="token punctuation">{</span> </span><span class="code-line"> allowedChecks <span class="token operator">:=</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token builtin">bool</span><span class="token punctuation">{</span><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> check <span class="token operator">:=</span> <span class="token keyword">range</span> checks <span class="token punctuation">{</span> </span><span class="code-line"> b <span class="token operator">:=</span> <span class="token boolean">true</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>check<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">1</span> <span class="token operator">&amp;&amp;</span> check<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token char">&#x27;-&#x27;</span> <span class="token punctuation">{</span> </span><span class="code-line"> b <span class="token operator">=</span> <span class="token boolean">false</span> </span><span class="code-line"> check <span class="token operator">=</span> check<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">:</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> check <span class="token operator">==</span> <span class="token string">&quot;*&quot;</span> <span class="token operator">||</span> check <span class="token operator">==</span> <span class="token string">&quot;all&quot;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// Match all</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> c <span class="token operator">:=</span> <span class="token keyword">range</span> analyzers <span class="token punctuation">{</span> </span><span class="code-line"> allowedChecks<span class="token punctuation">[</span>c<span class="token punctuation">]</span> <span class="token operator">=</span> b </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> strings<span class="token punctuation">.</span><span class="token function">HasSuffix</span><span class="token punctuation">(</span>check<span class="token punctuation">,</span> <span class="token string">&quot;*&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// Glob</span> </span><span class="code-line"> prefix <span class="token operator">:=</span> check<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token function">len</span><span class="token punctuation">(</span>check<span class="token punctuation">)</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span> </span><span class="code-line"> isCat <span class="token operator">:=</span> strings<span class="token punctuation">.</span><span class="token function">IndexFunc</span><span class="token punctuation">(</span>prefix<span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>r <span class="token builtin">rune</span><span class="token punctuation">)</span> <span class="token builtin">bool</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> unicode<span class="token punctuation">.</span><span class="token function">IsNumber</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> a <span class="token operator">:=</span> <span class="token keyword">range</span> analyzers <span class="token punctuation">{</span> </span><span class="code-line"> idx <span class="token operator">:=</span> strings<span class="token punctuation">.</span><span class="token function">IndexFunc</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>r <span class="token builtin">rune</span><span class="token punctuation">)</span> <span class="token builtin">bool</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> unicode<span class="token punctuation">.</span><span class="token function">IsNumber</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> isCat <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// Glob is S*, which should match S1000 but not SA1000</span> </span><span class="code-line"> cat <span class="token operator">:=</span> a<span class="token punctuation">[</span><span class="token punctuation">:</span>idx<span class="token punctuation">]</span> </span><span class="code-line"> <span class="token keyword">if</span> prefix <span class="token operator">==</span> cat <span class="token punctuation">{</span> </span><span class="code-line"> allowedChecks<span class="token punctuation">[</span>a<span class="token punctuation">]</span> <span class="token operator">=</span> b </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// Glob is S1*</span> </span><span class="code-line"> <span class="token keyword">if</span> strings<span class="token punctuation">.</span><span class="token function">HasPrefix</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> prefix<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> allowedChecks<span class="token punctuation">[</span>a<span class="token punctuation">]</span> <span class="token operator">=</span> b </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// Literal check name</span> </span><span class="code-line"> allowedChecks<span class="token punctuation">[</span>check<span class="token punctuation">]</span> <span class="token operator">=</span> b </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword">return</span> allowedChecks </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p><code>filterAnalyzerNames()</code> 实际上会被 <code>setupStaticCheckAnalyzers()</code> 调用, 其实只是在 <code>filterAnalyzerNames</code> 的基础上, 针对被启用的 <code>Analyzer</code> 设置了一下go version (<code>setAnalyzerGoVersion</code>) :</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function">setupStaticCheckAnalyzers</span><span class="token punctuation">(</span>src <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">*</span>lint<span class="token punctuation">.</span>Analyzer<span class="token punctuation">,</span> goVersion <span class="token builtin">string</span><span class="token punctuation">,</span> checks <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">*</span>analysis<span class="token punctuation">.</span>Analyzer <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">var</span> names <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> a <span class="token operator">:=</span> <span class="token keyword">range</span> src <span class="token punctuation">{</span> </span><span class="code-line"> names <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>names<span class="token punctuation">,</span> a<span class="token punctuation">.</span>Analyzer<span class="token punctuation">.</span>Name<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> filter <span class="token operator">:=</span> <span class="token function">filterAnalyzerNames</span><span class="token punctuation">(</span>names<span class="token punctuation">,</span> checks<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">var</span> ret <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">*</span>analysis<span class="token punctuation">.</span>Analyzer </span><span class="code-line"> <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> a <span class="token operator">:=</span> <span class="token keyword">range</span> src <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> filter<span class="token punctuation">[</span>a<span class="token punctuation">.</span>Analyzer<span class="token punctuation">.</span>Name<span class="token punctuation">]</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">setAnalyzerGoVersion</span><span class="token punctuation">(</span>a<span class="token punctuation">.</span>Analyzer<span class="token punctuation">,</span> goVersion<span class="token punctuation">)</span> </span><span class="code-line"> ret <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>ret<span class="token punctuation">,</span> a<span class="token punctuation">.</span>Analyzer<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">return</span> ret </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>其后我们看下那几个 new 都差不多, 都会调用 <code>setupStaticCheckAnalyzers()</code>:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function">NewStaticcheck</span><span class="token punctuation">(</span>settings <span class="token operator">*</span>config<span class="token punctuation">.</span>StaticCheckSettings<span class="token punctuation">)</span> <span class="token operator">*</span>goanalysis<span class="token punctuation">.</span>Linter <span class="token punctuation">{</span> </span><span class="code-line"> cfg <span class="token operator">:=</span> <span class="token function">staticCheckConfig</span><span class="token punctuation">(</span>settings<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> analyzers <span class="token operator">:=</span> <span class="token function">setupStaticCheckAnalyzers</span><span class="token punctuation">(</span>staticcheck<span class="token punctuation">.</span>Analyzers<span class="token punctuation">,</span> <span class="token function">getGoVersion</span><span class="token punctuation">(</span>settings<span class="token punctuation">)</span><span class="token punctuation">,</span> cfg<span class="token punctuation">.</span>Checks<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">return</span> goanalysis<span class="token punctuation">.</span><span class="token function">NewLinter</span><span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;staticcheck&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;Staticcheck is a go vet on steroids, applying a ton of static analysis checks&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> analyzers<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token boolean">nil</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">WithLoadMode</span><span class="token punctuation">(</span>goanalysis<span class="token punctuation">.</span>LoadModeTypesInfo<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function">NewStylecheck</span><span class="token punctuation">(</span>settings <span class="token operator">*</span>config<span class="token punctuation">.</span>StaticCheckSettings<span class="token punctuation">)</span> <span class="token operator">*</span>goanalysis<span class="token punctuation">.</span>Linter <span class="token punctuation">{</span> </span><span class="code-line"> cfg <span class="token operator">:=</span> <span class="token function">staticCheckConfig</span><span class="token punctuation">(</span>settings<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// `scconfig.Analyzer` is a singleton, then it&#x27;s not possible to have more than one instance for all staticcheck &quot;sub-linters&quot;.</span> </span><span class="code-line"> <span class="token comment">// When we will merge the 4 &quot;sub-linters&quot;, the problem will disappear: https://github.com/golangci/golangci-lint/issues/357</span> </span><span class="code-line"> <span class="token comment">// Currently only stylecheck analyzer has a configuration in staticcheck.</span> </span><span class="code-line"> scconfig<span class="token punctuation">.</span>Analyzer<span class="token punctuation">.</span>Run <span class="token operator">=</span> <span class="token keyword">func</span><span class="token punctuation">(</span>pass <span class="token operator">*</span>analysis<span class="token punctuation">.</span>Pass<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token keyword">interface</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> cfg<span class="token punctuation">,</span> <span class="token boolean">nil</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> analyzers <span class="token operator">:=</span> <span class="token function">setupStaticCheckAnalyzers</span><span class="token punctuation">(</span>stylecheck<span class="token punctuation">.</span>Analyzers<span class="token punctuation">,</span> <span class="token function">getGoVersion</span><span class="token punctuation">(</span>settings<span class="token punctuation">)</span><span class="token punctuation">,</span> cfg<span class="token punctuation">.</span>Checks<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">return</span> goanalysis<span class="token punctuation">.</span><span class="token function">NewLinter</span><span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;stylecheck&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;Stylecheck is a replacement for golint&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> analyzers<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token boolean">nil</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">WithLoadMode</span><span class="token punctuation">(</span>goanalysis<span class="token punctuation">.</span>LoadModeTypesInfo<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p><a href="https://github.com/golangci/golangci-lint/commit/7705f82591bdc71500802ce1b0fee4ef6726bbcc">https://github.com/golangci/golangci-lint/commit/7705f82591bdc71500802ce1b0fee4ef6726bbcc</a></p><p>Update megacheck to the latest version Also do following improvements:</p><ul><li>show proper sublinter name for megacheck sublinters</li><li>refactor and make more simple and robust megacheck merging/optimizing</li><li>improve handling of unknown linter names in //nolint directives</li><li>minimize diff of our megacheck version from the upstream, golang/go#29612 blocks usage of the upstream version</li><li>support the new <code>stylecheck</code> linter</li><li>improve tests coverage for megacheck and nolint related cases</li><li>update and use upstream versions of unparam and interfacer instead of forked ones</li><li>don&#x27;t use golangci/tools repo anymore</li><li>fix newly found issues after updating linters</li></ul><p>Also should be noted that megacheck works much faster and consumes less memory in the newest release, therefore golangci-lint works noticeably faster and consumes less memory for large repos.</p><p>Relates: #314 master (#352) v1.40.1 v1.40.0 v1.39.0 v1.38.0 v1.37.1 v1.37.0 v1.36.0 v1.35.2 v1.35.1 v1.35.0 v1.34.1 v1.34.0 v1.33.2 v1.33.1 v1.33.0 v1.32.2 v1.32.1 v1.32.0 v1.31.0 v1.30.0 v1.29.0 v1.28.3 v1.28.2 v1.28.1 v1.28.0 v1.27.0 v1.26.0 v1.25.1 v1.25.0 v1.24.0 v1.23.8 v1.23.7 v1.23.6 v1.23.5 v1.23.4 v1.23.3 v1.23.2 v1.23.1 v1.23.0 v1.22.2 v1.22.1 v1.22.0 v1.21.0 v1.20.1 v1.20.0 v1.19.1 v1.19.0 v1.18.0 v1.17.1 v1.17.0 v1.16.0 v1.15.0 v1.14.0 v1.13.2 v1.13.1 v1.13</p><h2 id="总结"><a href="#总结" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>总结</h2><ol><li><p>在 golangci-lint 当前版本 (v1.40.1)里, <code>megacheck = [gosimple staticcheck unused]</code></p></li><li><p><code>staticcheck</code> = staticcheck package (而不是四合一的 当前真正的 staticcheck cmd的功能)</p></li><li><p><code>stylecheck</code> 目前我们还没办法启用,因为当前无法给它配置需要禁用的一些规则. 只能等下一个 golangci-lint 版本 (如果它把上面我说到的代码合并了)</p></li></ol><p>如是 当前 master 分支的代码被合并了,那么是可以使用以下配置的:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line">linters-settings: </span><span class="code-line"> stylecheck: </span><span class="code-line"> checks: </span><span class="code-line"> - all </span><span class="code-line"> - <span class="token string">&#x27;-ST1000&#x27;</span> </span><span class="code-line"> - <span class="token string">&#x27;-ST1003&#x27;</span> </span><span class="code-line"> - <span class="token string">&#x27;-ST1016&#x27;</span> </span><span class="code-line"> - <span class="token string">&#x27;-ST1020&#x27;</span> </span><span class="code-line"> - <span class="token string">&#x27;-ST1021&#x27;</span> </span><span class="code-line"> - <span class="token string">&#x27;-ST1022&#x27;</span> </span><span class="code-line"> - <span class="token string">&#x27;-ST1023&#x27;</span> </span><span class="code-line"> dot-import-whitelist: <span class="token punctuation">[</span><span class="token punctuation">]</span> </span><span class="code-line"> http-status-code-whitelist: <span class="token punctuation">[</span><span class="token punctuation">]</span> </span></code></pre></div><ol start="4"><li>我们期待 golangci-lint 新的 2.0 版本里将真正的 四合一版本的 staticcheck 集成进来,这样就没有必要像现在这样,针对同一个 linter 的同样的配置要写四遍了。</li></ol><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://staticcheck.io/">https://staticcheck.io/</a></p><p><a href="https://github.com/golangci/golangci-lint">https://github.com/golangci/golangci-lint</a></p><p><a href="https://golangci-lint.run/">https://golangci-lint.run/</a></p> Sun, 06 Jun 2021 16:00:33 GMT ttyS3 golanggolangic-lintlinterstaticcheck https://ttys3.dev/blog/awesome-image-process-server-written-in-golang-or-rust 分享几个基于Golang/Rust的图片处理开源项目 https://ttys3.dev/blog/awesome-image-process-server-written-in-golang-or-rust <h2 id="1-imgproxyimgproxy-golang-46k-star"><a href="#1-imgproxyimgproxy-golang-46k-star" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. imgproxy/imgproxy (golang, 4.6K star)</h2><p><a href="https://github.com/imgproxy/imgproxy">imgproxy</a> 目前有 4.6K star</p><p><a href="https://github.com/imgproxy/imgproxy">https://github.com/imgproxy/imgproxy</a></p><blockquote><p>Fast and secure standalone server for resizing and converting remote images</p><p>imgproxy 是一个快速安全的独立服务器,用于调整远程图像的大小和转换远程图像。 imgproxy 的主要原则是简单,速度和安全性。</p><p>imgproxy 只做一件事 —— 调整远程图像的大小 —— 而且做得很好。 当您需要动态调整多个图像的大小以使其与您的应用程序设计匹配时,它非常有用,而无需准备大量缓存的调整大小的图像或每次设计更改时都重新执行。</p><p>imgproxy是一个go应​​用程序,准备安装并在任何Unix环境中使用 - 也可以使用Docker容器化。</p></blockquote><h3 id="简单"><a href="#简单" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>简单</h3><blockquote><p>&quot;No code is better than no code.&quot;</p></blockquote><p>这句话我保持原样不做翻译,任何翻译都会导致变味。简单来说,imgproxy 只会包含那些必须的功能,而一些补充性可有可无的功能就不会包含进来。</p><p>imgproxy 仅包括用于图像处理,微调和安全性的必须具有的功能。</p><p>它的简单体现在哪里呢?</p><ol><li><p>能方很容易使用CSS3完成功能的,坚决不集成,比如 rotate, flip  和应用蒙板层这类操作。</p></li><li><p>不内置HTTP缓存功能,因为这个目的很容易通过 CDN 或者 专门的缓存代理服务器 来实现</p></li><li><p>不会试图内置实现所有功能,比如 https 支持,因为这个很容易就可以通过一些专业的 http 代理服务器来实现, 比如 nginx</p></li></ol><p>拥有内置的所有内容 - 例如HTTPS支持可能是有用的 - 但是解决这一问题的简单方法是使用诸如nginx等代理HTTP服务器。</p><h2 id="高效"><a href="#高效" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>高效</h2><p>高效处理图片的主要原因是,它的图片处理并不是通过原生golang来实现的,而是通过调用C库<code>libvips</code>,<code>libvips</code>号称是所有图片处理库里速度最快的。(没错, 在缩放图片这种操作上, ImageMagick 或 GraphicsMagick 也 PK 不过 libvips)</p><p>官方甚至提供了一个 <a href="https://github.com/imgproxy/imgproxy/blob/master/BENCHMARK.md">benchmark</a> 可供参考:</p><table><thead><tr><th>Tool</th><th>Time taken for tests<br/>(sec)</th><th>Requests per second</th><th>Time per request<br/>(ms, mean)</th><th>Memory peak usage<br/>(MB)</th><th>Result file size<br/>(KB)</th></tr></thead><tbody><tr><td>imgproxy</td><td>103.405</td><td>9.67</td><td>413.618</td><td>194</td><td>43.51</td></tr><tr><td>thumbor</td><td>160.505</td><td>6.23</td><td>642.021</td><td>461</td><td>45.10</td></tr><tr><td>imaginary</td><td>104.873</td><td>9.54</td><td>419.494</td><td>562</td><td>92.93</td></tr><tr><td>Pilbox</td><td>179.482</td><td>5.57</td><td>717.927</td><td>1060</td><td>95.64</td></tr><tr><td>picfit</td><td>1220.412</td><td>0.82</td><td>4881.646</td><td>1934</td><td>98.67</td></tr><tr><td>imageproxy</td><td>1209.361</td><td>0.83</td><td>4837.443</td><td>2392</td><td>98.74</td></tr></tbody></table><h2 id="安全"><a href="#安全" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安全</h2><p>在安全方面,大量处理远程图像是一件潜在的危险事情。</p><p>* imgproxy 在下载时会检查图像类型和“真实”尺寸,因此如果图像格式未知或尺寸太大(有一个设置),则不会完全下载图像。 这就是 imgproxy 如何保护您免受所谓的“图像炸弹”的侵害,例如在 <a href="https://www.bamsoftware.com/hacks/deflate.html">https://www.bamsoftware.com/hacks/deflate.html </a>中描述的那些。</p><p>* imgproxy 使用签名保护图像 URL,因此攻击者无法通过请求多个图像调整大小来引发拒绝服务攻击。</p><p>* imgproxy 支持通过 HTTP header 进行授权。 这可以防止攻击者直接使用 imgproxy,但允许通过 CDN 或缓存服务器使用它——只需向代理或 CDN 配置添加 header 即可。</p><p>--------------------------------------------------------------------------------------</p><p>相关文档:</p><p>* <a href="https://docs.imgproxy.net/">https://docs.imgproxy.net/</a></p><p>* <a href="https://evilmartians.com/chronicles/introducing-imgproxy">https://evilmartians.com/chronicles/introducing-imgproxy</a></p><h2 id="2-imazenimageflow-rust-35k-star"><a href="#2-imazenimageflow-rust-35k-star" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. imazen/imageflow (rust, 3.5K star)</h2><p><a href="https://docs.imageflow.io/">https://docs.imageflow.io/</a></p><p><a href="https://github.com/imazen/imageflow">https://github.com/imazen/imageflow</a></p><p><a href="https://docs.imageflow.io/querystring/introduction.html">https://docs.imageflow.io/querystring/introduction.html</a></p><p>高性能图片处理服务器,包含imageflow_server, imageflow_tool, and libimageflow</p><p><a href="https://hub.docker.com/r/imazen/imageflow_tool/"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/imazen/imageflow_tool.svg"/></a></p><p><a href="https://hub.docker.com/r/imazen/imageflow_server_unsecured/"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/imazen/imageflow_server_unsecured.svg"/></a></p><p><a href="https://github.com/imazen/imageflow/releases"><img alt="view releases" src="https://img.shields.io/badge/-download%20binaries%20for%20windows,%20mac,%20or%20linux-green.svg"/></a></p><p><a href="https://imageresizing.net/pricing"><img alt="license: Choose AGPLv3 or Commercial" src="https://img.shields.io/badge/license-Choose%20AGPLv3%20or%20Commercial-green.svg"/></a></p><ul><li><strong>imageflow_tool</strong> is a command-line tool for experimenting, running batch jobs, or when you want process isolation. Up to 17x faster than ImageMagick. Also produces smaller files at higher quality.</li><li><strong>imageflow_server</strong> can run JSON jobs or manipulate images in-flight (e.g.<code>/bucket/img.jpg?w=200</code>) for direct use from HTML. Source images can reside in blob storage, on another server, or on the filesystem. However, for production use, we recommend using <a href="https://github.com/imazen/imageflow-dotnet-server">Imageflow.NET Server</a>, which is far more feature-rich and doesn&#x27;t need a reverse proxy in front for security.</li><li><strong>libimageflow</strong> is for direct (in-process) use from <em>your</em> programming language. See our <strong><a href="https://github.com/imazen/imageflow-node">Node bindings</a></strong>, <strong><a href="https://github.com/imazen/imageflow-go">Go bindings</a></strong>, <strong><a href="https://github.com/Dealermade/imageflow-scala">Scala bindings</a></strong>, <strong><a href="https://github.com/naps62/imageflow_ex">Elixir bindings</a></strong>, or <strong><a href="https://github.com/imazen/imageflow-dotnet">.NET bindings</a></strong>. If we don&#x27;t already have bindings for your language, consider spending a day to add them. Imageflow has a simple C-compatible ABI, of which only 4 methods are needed to implement bindings.</li></ul><h2 id="3--h2nonimaginary-golang-37k-star"><a href="#3--h2nonimaginary-golang-37k-star" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. h2non/imaginary (golang, 3.7K star)</h2><p><a href="https://github.com/h2non/imaginary">https://github.com/h2non/imaginary</a></p><p><a href="https://fly.io/launch/github/h2non/imaginary">https://fly.io/launch/github/h2non/imaginary</a></p><blockquote><p>Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing</p></blockquote><p>imaginary 也是用的 <code>libvips</code></p><p>容器化支持较好。</p><h2 id="supported-image-operations"><a href="#supported-image-operations" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Supported image operations</h2><ul><li>Resize</li><li>Enlarge</li><li>Crop</li><li>SmartCrop (based on <a href="https://github.com/jcupitt/libvips/blob/master/libvips/conversion/smartcrop.c">libvips built-in algorithm</a>)</li><li>Rotate (with auto-rotate based on EXIF orientation)</li><li>AutoRotate with further image transformations (based on EXIF metadata orientation)</li><li>Flip (with auto-flip based on EXIF metadata)</li><li>Flop</li><li>Zoom</li><li>Thumbnail</li><li>Fit</li><li><a href="https://github.com/h2non/imaginary#get--post-pipeline">Pipeline</a> of multiple independent image transformations in a single HTTP request.</li><li>Configurable image area extraction</li><li>Embed/Extend image, supporting multiple modes (white, black, mirror, copy or custom background color)</li><li>Watermark (customizable by text)</li><li>Watermark image</li><li>Custom output color space (RGB, black/white...)</li><li>Format conversion (with additional quality/compression settings)</li><li>Info (image size, format, orientation, alpha...)</li><li>Reply with default or custom placeholder image in case of error.</li><li>Blur</li></ul><h2 id="4-thoaspicfit-golang-15k-star"><a href="#4-thoaspicfit-golang-15k-star" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4. thoas/picfit (golang, 1.5K star)</h2><p>picfit is a reusable Go server to manipulate images (resize, thumbnail, etc.).</p><p>It will act as a proxy on your storage engine and will be served ideally behind an HTTP cache system like <a href="https://www.varnish-cache.org/">varnish</a>.</p><p>It supports multiple <a href="https://github.com/ulule/gostorages">storage backends</a> and multiple <a href="https://github.com/ulule/gokvstores">key/value stores</a>.</p><p><code>[KVSTORE]</code> can be:</p><ul><li><strong>redis</strong> - generated keys stored in <a href="http://redis.io/">Redis</a>, see <a href="https://github.com/thoas/picfit#store-images-on-amazon-s3-keys-in-redis-and-shard-filename">below</a> how you can customize connection parameters</li><li><strong>cache</strong> - generated keys stored in an in-memory cache</li><li><strong>redis-cluster</strong> - generated keys stored in <a href="https://redis.io/topics/cluster-tutorial">Redis cluster</a></li></ul><p><code>[STORAGE]</code> can be:</p><ul><li><strong>fs</strong> - generated images stored in your File system</li><li><strong>http+fs</strong> - generated images stored in your File system and loaded using HTTP protocol</li><li><strong>s3</strong> - generated images stored in Amazon S3</li><li><strong>dos3</strong> - generated images stored in DigitalOcean S3</li><li><strong>gcs</strong> - generated images stored in Google Cloud Storage</li><li><strong>http+s3</strong> - generated images stored in Amazon S3 and loaded using HTTP protocol</li><li><strong>http+dos3</strong> - generated images stored in DigitalOcean S3 and loaded using HTTP protocol</li></ul><p><a href=""></a></p><h2 id="5-pierrreimageserver-golang--19k-star"><a href="#5-pierrreimageserver-golang--19k-star" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>5. pierrre/imageserver (golang, 1.9K star)</h2><p><a href="https://github.com/pierrre/imageserver">imageserver</a> 并不是一个到手就能用的服务,而是一个golang module.</p><h2 id="features"><a href="#features" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Features</h2><ul><li>HTTP server</li><li>Resize (<a href="https://github.com/disintegration/gift">GIFT</a>, <a href="https://github.com/nfnt/resize">nfnt resize</a>, <a href="http://www.graphicsmagick.org/">Graphicsmagick</a>)</li><li>Rotate</li><li>Crop</li><li>Convert (JPEG, GIF (animated), PNG , BMP, TIFF, ...)</li><li>Cache (<a href="https://github.com/golang/groupcache">groupcache</a>, <a href="https://github.com/garyburd/redigo">Redis</a>, <a href="https://github.com/bradfitz/gomemcache">Memcache</a>, in memory)</li><li>Gamma correction</li><li>Fully modular</li></ul><p>不过集成使用它也比较简单:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// https://github.com/pierrre/imageserver/blob/master/examples/simple/simple.go</span> </span><span class="code-line"><span class="token comment">// Package simple provides a simple example.</span> </span><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;net/http&quot;</span>https<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>github<span class="token punctuation">.</span>com<span class="token operator">/</span>imgproxy<span class="token operator">/</span>imgproxy </span><span class="code-line"> </span><span class="code-line"> <span class="token string">&quot;github.com/pierrre/imageserver&quot;</span> </span><span class="code-line"> imageserver_http <span class="token string">&quot;github.com/pierrre/imageserver/http&quot;</span> </span><span class="code-line"> imageserver_http_gift <span class="token string">&quot;github.com/pierrre/imageserver/http/gift&quot;</span> </span><span class="code-line"> imageserver_http_image <span class="token string">&quot;github.com/pierrre/imageserver/http/image&quot;</span> </span><span class="code-line"> imageserver_image <span class="token string">&quot;github.com/pierrre/imageserver/image&quot;</span> </span><span class="code-line"> <span class="token boolean">_</span> <span class="token string">&quot;github.com/pierrre/imageserver/image/gif&quot;</span> </span><span class="code-line"> imageserver_image_gift <span class="token string">&quot;github.com/pierrre/imageserver/image/gift&quot;</span> </span><span class="code-line"> <span class="token boolean">_</span> <span class="token string">&quot;github.com/pierrre/imageserver/image/jpeg&quot;</span> </span><span class="code-line"> <span class="token boolean">_</span> <span class="token string">&quot;github.com/pierrre/imageserver/image/png&quot;</span> </span><span class="code-line"> imageserver_testdata <span class="token string">&quot;github.com/pierrre/imageserver/testdata&quot;</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> http<span class="token punctuation">.</span><span class="token function">Handle</span><span class="token punctuation">(</span><span class="token string">&quot;/&quot;</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>imageserver_http<span class="token punctuation">.</span>Handler<span class="token punctuation">{</span> </span><span class="code-line"> Parser<span class="token punctuation">:</span> imageserver_http<span class="token punctuation">.</span><span class="token function">ListParser</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span>imageserver_http<span class="token punctuation">.</span>Parser<span class="token punctuation">{</span> </span><span class="code-line"> <span class="token operator">&amp;</span>imageserver_http<span class="token punctuation">.</span>SourceParser<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">&amp;</span>imageserver_http_gift<span class="token punctuation">.</span>ResizeParser<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">&amp;</span>imageserver_http_image<span class="token punctuation">.</span>FormatParser<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token operator">&amp;</span>imageserver_http_image<span class="token punctuation">.</span>QualityParser<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> Server<span class="token punctuation">:</span> <span class="token operator">&amp;</span>imageserver<span class="token punctuation">.</span>HandlerServer<span class="token punctuation">{</span> </span><span class="code-line"> Server<span class="token punctuation">:</span> imageserver_testdata<span class="token punctuation">.</span>Server<span class="token punctuation">,</span> </span><span class="code-line"> Handler<span class="token punctuation">:</span> <span class="token operator">&amp;</span>imageserver_image<span class="token punctuation">.</span>Handler<span class="token punctuation">{</span> </span><span class="code-line"> Processor<span class="token punctuation">:</span> <span class="token operator">&amp;</span>imageserver_image_gift<span class="token punctuation">.</span>ResizeProcessor<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span>https<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>github<span class="token punctuation">.</span>com<span class="token operator">/</span>imgproxy<span class="token operator">/</span>imgproxy </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span><span class="code-line"> err <span class="token operator">:=</span> http<span class="token punctuation">.</span><span class="token function">ListenAndServe</span><span class="token punctuation">(</span><span class="token string">&quot;:8080&quot;</span><span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">panic</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div> Sun, 06 Jun 2021 03:57:59 GMT ttyS3 imageresizelibvipsimgproxyimageflowimageservergolangrust https://ttys3.dev/blog/tool Tool https://ttys3.dev/blog/tool <hr/><h2 id="格式转换"><a href="#格式转换" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>格式转换</h2><p>toml to yaml: <a href="https://www.convertsimple.com/convert-toml-to-yaml/">https://www.convertsimple.com/convert-toml-to-yaml/</a></p><p>yaml to toml: <a href="https://www.convertsimple.com/convert-yaml-to-toml/">https://www.convertsimple.com/convert-yaml-to-toml/</a></p><p>json to toml: <a href="https://www.convertsimple.com/convert-json-to-toml/">https://www.convertsimple.com/convert-json-to-toml/</a></p><p>json to yaml: <a href="https://transform.tools/json-to-yaml">https://transform.tools/json-to-yaml</a></p><p><a href="https://transform.tools/json-schema-to-protobuf">https://transform.tools/json-schema-to-protobuf</a></p><p><a href="https://transform.tools/js-object-to-json">https://transform.tools/js-object-to-json</a></p><p>transform is open source: <a href="https://github.com/ritz078/transform">https://github.com/ritz078/transform</a></p><hr/><h2 id="语言相关"><a href="#语言相关" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>语言相关</h2><p><a href="https://transform.tools/json-to-rust-serde">https://transform.tools/json-to-rust-serde</a></p><p><a href="https://transform.tools/json-to-go-bson">https://transform.tools/json-to-go-bson</a></p><p><a href="https://transform.tools/json-to-go">https://transform.tools/json-to-go</a></p><p><a href="https://mholt.github.io/json-to-go/">https://mholt.github.io/json-to-go/</a></p><p><a href="https://mholt.github.io/curl-to-go/">https://mholt.github.io/curl-to-go/</a></p><hr/><p>json <a href="https://jsoneditoronline.org/">https://jsoneditoronline.org/</a></p><p>json 格式化神器 <a href="https://jsonformatter.org/">https://jsonformatter.org/</a></p><p>Protobuf decode <a href="https://protobuf-decoder.netlify.app/">https://protobuf-decoder.netlify.app/</a></p><p>markdown 画图 mermaid-live-editor <a href="https://mermaid-js.github.io/mermaid-live-editor">https://mermaid-js.github.io/mermaid-live-editor</a></p><p>汇编分析 Godbolt Compiler Explorer <a href="https://godbolt.org/">https://godbolt.org/</a></p><p>数学神器 Wolframalpha <a href="https://www.wolframalpha.com/">https://www.wolframalpha.com/</a></p><p>在线ps 图片 <a href="https://pc.meitu.com/design/edit">https://pc.meitu.com/design/edit</a></p><p>包依赖分析 <a href="https://deps.dev/">https://deps.dev/</a></p><p>Regex101 最好用的正则测试工具 <a href="https://regex101.com/">https://regex101.com/</a></p><h2 id="static-site-generator"><a href="#static-site-generator" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>static site generator</h2><p><a href="https://jamstack.org/generators/">https://jamstack.org/generators/</a></p><p><a href="https://github.com/gohugoio/hugo">https://github.com/gohugoio/hugo</a></p><p><a href="https://github.com/getzola/zola">https://github.com/getzola/zola</a></p><h2 id="静态博客托管"><a href="#静态博客托管" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>静态博客托管</h2><p><a href="https://www.netlify.com/">https://www.netlify.com/</a></p><p>Cloudflare Pages <a href="https://developers.cloudflare.com/pages/getting-started">https://developers.cloudflare.com/pages/getting-started</a></p><p><a href="https://pages.cloudflare.com/#pricing">https://pages.cloudflare.com/#pricing</a></p><p><a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-zola-site#deploying-with-cloudflare-pages">https://developers.cloudflare.com/pages/framework-guides/deploy-a-zola-site#deploying-with-cloudflare-pages</a></p><p><a href="https://developers.cloudflare.com/pages/platform/limits">https://developers.cloudflare.com/pages/platform/limits</a></p><p>bandwidth: Unlimited bandwidth Builds: deploy up to 500 times per month on the free plan Maximum file size: 25MB Custom domains: a maximum of ten (10) custom domains per project</p><p><a href="https://vercel.com/">https://vercel.com/</a></p><p><a href="https://render.com/">https://render.com/</a></p><p><a href="https://help.github.com/articles/what-is-github-pages/">https://help.github.com/articles/what-is-github-pages/</a></p><p>AWS Amplify <a href="https://aws.amazon.com/amplify/pricing/">https://aws.amazon.com/amplify/pricing/</a></p><p>-- EOF</p> Sun, 06 Jun 2021 00:00:00 GMT ttyS3 https://ttys3.dev/blog/add-mermaid-shortcode-to-hugo 给 Hugo 博客添加 mermaid 短代码支持 https://ttys3.dev/blog/add-mermaid-shortcode-to-hugo <p>首先,看下效果,就是下面这样(RSS 订阅用户可能看不到效果,请点击查看原文):</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token operator">&lt;</span> mermaid <span class="token operator">&gt;</span><span class="token punctuation">}</span><span class="token punctuation">}</span> </span><span class="code-line">sequenceDiagram </span><span class="code-line"> participant <span class="token maybe-class-name">Alice</span> </span><span class="code-line"> participant <span class="token maybe-class-name">Bob</span> </span><span class="code-line"> <span class="token maybe-class-name">Alice</span><span class="token operator">-</span><span class="token operator">&gt;&gt;</span><span class="token maybe-class-name">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Hello</span> <span class="token maybe-class-name">John</span><span class="token punctuation">,</span> how are you<span class="token operator">?</span> </span><span class="code-line"> loop <span class="token maybe-class-name">Healthcheck</span> </span><span class="code-line"> <span class="token maybe-class-name">John</span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token maybe-class-name">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Fight</span> against hypochondria </span><span class="code-line"> end </span><span class="code-line"> <span class="token maybe-class-name">Note</span> right <span class="token keyword">of</span> <span class="token literal-property property">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Rational</span> thoughts prevail<span class="token operator spread">...</span> </span><span class="code-line"> <span class="token maybe-class-name">John</span><span class="token operator">--</span><span class="token operator">&gt;</span><span class="token maybe-class-name">Alice</span><span class="token operator">:</span> <span class="token maybe-class-name">Great</span><span class="token operator">!</span> </span><span class="code-line"> <span class="token maybe-class-name">John</span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token maybe-class-name">Bob</span><span class="token operator">:</span> <span class="token maybe-class-name">How</span> about you<span class="token operator">?</span> </span><span class="code-line"> <span class="token maybe-class-name">Bob</span><span class="token operator">--</span><span class="token operator">&gt;</span><span class="token maybe-class-name">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Jolly</span> good<span class="token operator">!</span> </span><span class="code-line"><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token operator">&lt;</span> <span class="token operator">/</span>mermaid <span class="token operator">&gt;</span><span class="token punctuation">}</span><span class="token punctuation">}</span> </span></code></pre></div><p>源代码取自 <a href="https://learn.netlify.app/en/shortcodes/mermaid/">https://learn.netlify.app/en/shortcodes/mermaid/</a> , 如下:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">sequenceDiagram </span><span class="code-line"> participant <span class="token maybe-class-name">Alice</span> </span><span class="code-line"> participant <span class="token maybe-class-name">Bob</span> </span><span class="code-line"> <span class="token maybe-class-name">Alice</span><span class="token operator">-</span><span class="token operator">&gt;&gt;</span><span class="token maybe-class-name">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Hello</span> <span class="token maybe-class-name">John</span><span class="token punctuation">,</span> how are you<span class="token operator">?</span> </span><span class="code-line"> loop <span class="token maybe-class-name">Healthcheck</span> </span><span class="code-line"> <span class="token maybe-class-name">John</span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token maybe-class-name">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Fight</span> against hypochondria </span><span class="code-line"> end </span><span class="code-line"> <span class="token maybe-class-name">Note</span> right <span class="token keyword">of</span> <span class="token literal-property property">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Rational</span> thoughts prevail<span class="token operator spread">...</span> </span><span class="code-line"> <span class="token maybe-class-name">John</span><span class="token operator">--</span><span class="token operator">&gt;</span><span class="token maybe-class-name">Alice</span><span class="token operator">:</span> <span class="token maybe-class-name">Great</span><span class="token operator">!</span> </span><span class="code-line"> <span class="token maybe-class-name">John</span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token maybe-class-name">Bob</span><span class="token operator">:</span> <span class="token maybe-class-name">How</span> about you<span class="token operator">?</span> </span><span class="code-line"> <span class="token maybe-class-name">Bob</span><span class="token operator">--</span><span class="token operator">&gt;</span><span class="token maybe-class-name">John</span><span class="token operator">:</span> <span class="token maybe-class-name">Jolly</span> good<span class="token operator">!</span> </span></code></pre></div><h2 id="短代码使用方法"><a href="#短代码使用方法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>短代码使用方法</h2><div class="relative"><pre><code class="code-highlight language-go-html-template"><span class="code-line">{{&lt;/* mermaid */&gt;}} </span><span class="code-line">// 中间写mermaid </span><span class="code-line">{{&lt;/* /mermaid */&gt;}} </span></code></pre></div><p>看上去好像不太直观啊,没错,官方也考虑到了这一点,给送上了 mermaid-live-editor</p><p><a href="https://mermaid-js.github.io/mermaid-live-editor">https://mermaid-js.github.io/mermaid-live-editor</a></p><p>使用 mermaid-live-editor,可以实时预览效果,如果不知道下手,里面还有快速demo供使用。</p><div><img alt="" src="https://ttys3.dev/static/assets/mermaid-live-editor-2021-06-06_01-51-K3MKTI2N.png" width="2307" height="1472"/></div><h2 id="集成到-hugo"><a href="#集成到-hugo" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>集成到 Hugo</h2><p>目的: 最简化集成, 不需要增加 Hugo 配置, 不需要在 markdown front matter 里增加任何选项.</p><h3 id="增加-shortcode-模板"><a href="#增加-shortcode-模板" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>增加 shortcode 模板</h3><p>如果用 mermaid 官方的集成方法,会带来一个问题: 官方集成方法会导致我们的每个文章页面都会加载 mermaid.js ,但是 我们写博客的时候,并不是每个页面都需要加载 mermaid 这个 js, 只在文章里面包含 mermaid 代码时我们才需要加载。因此这里我们用 js 动态加载 mermaid.</p><p>首先,这个 js 我们也懒得放在主题里了,直接用 CDN 的:</p><p>去 <a href="https://www.jsdelivr.com/package/npm/mermaid">https://www.jsdelivr.com/package/npm/mermaid</a> 我们点开 dist 目录,然后找到完整版的js文件(注意不要看错了,选了 core 那个):</p><p><code>https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.min.js</code></p><p>新增加 shortcode, 目前我用的主题是 terminal, 因此在 themes/terminal 下新建:</p><p><code>layouts/shortcodes/mermaid.html</code> 文件,内容如下:</p><div class="relative"><pre><code class="code-highlight language-go-html-template"><span class="code-line">&lt;!-- https://github.com/matcornic/hugo-theme-learn/blob/master/layouts/shortcodes/mermaid.html --&gt; </span><span class="code-line">&lt;pre class=&quot;mermaid&quot; align=&quot;{{ if .Get &quot;align&quot; }}{{ .Get &quot;align&quot; }}{{ else }}center{{ end }}&quot;&gt;{{ safeHTML .Inner }}&lt;/pre&gt; </span></code></pre></div><p>这个 shortcode 代码基本上取自<a href="https://github.com/matcornic/hugo-theme-learn/blob/master/layouts/shortcodes/mermaid.html">这里</a>, 但是老灯这里把外层的 <code>div</code> 改成了 <code>pre</code></p><p>关于 <code>.Inner</code> 是啥, 可以参考<a href="https://gohugo.io/templates/shortcode-templates/#inner">这个文档</a></p><p><code>{{ $_hugo_config := `{ &quot;version&quot;: 1 }` }}</code> 我也一并移除了,这个是 shortcodes-with-markdown 才需要的,而我们这里面的内容都是直接给 js 处理的,并不需要 markdown 处理。 参考<a href="https://gohugo.io/content-management/shortcodes/#shortcodes-with-markdown">这里</a></p><h3 id="加载-mermaid-js"><a href="#加载-mermaid-js" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>加载 mermaid js</h3><p>网上大部分的模板都不够自动, 很多是需要在配置里选择是否加载 mermaid 的, 这里老灯写了个根据文章内容动态加载的 js .</p><p>修改模板的 footer.html 文件,增加 js:</p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line"> <span class="token keyword">const</span> <span class="token function function-variable">loadScript</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">url<span class="token punctuation">,</span> onloadFunction</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">var</span> newScript <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">createElement</span><span class="token punctuation">(</span><span class="token string">&quot;script&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> newScript<span class="token punctuation">.</span><span class="token property-access function method function-variable method-variable">onerror</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">oError</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">throw</span> <span class="token keyword">new</span> <span class="token class-name">URIError</span><span class="token punctuation">(</span><span class="token string">&quot;The script &quot;</span> <span class="token operator">+</span> oError<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">src</span> <span class="token operator">+</span> <span class="token string">&quot; didn&#x27;t load correctly.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>onloadFunction<span class="token punctuation">)</span> <span class="token punctuation">{</span> newScript<span class="token punctuation">.</span><span class="token property-access">onload</span> <span class="token operator">=</span> onloadFunction<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">head</span><span class="token punctuation">.</span><span class="token property-access function method">insertAdjacentElement</span><span class="token punctuation">(</span><span class="token string">&#x27;beforeend&#x27;</span><span class="token punctuation">,</span> newScript<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> newScript<span class="token punctuation">.</span><span class="token property-access">src</span> <span class="token operator">=</span> url<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// mermaid loader by ttys3.dev</span> </span><span class="code-line"> <span class="token keyword">const</span> <span class="token function function-variable">loadMermaidOnNeed</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">&#x27;.mermaid&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">loadScript</span><span class="token punctuation">(</span><span class="token string">&#x27;https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.min.js&#x27;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">head</span><span class="token punctuation">.</span><span class="token property-access function method">insertAdjacentHTML</span><span class="token punctuation">(</span><span class="token string">&quot;beforeend&quot;</span><span class="token punctuation">,</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">&lt;style&gt;.mermaid svg { background-color: #dadcd8 !important; }&lt;/style&gt;</span><span class="token string template-punctuation">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// default, dark, neutral, forest</span> </span><span class="code-line"> mermaid<span class="token punctuation">.</span><span class="token property-access function method">initialize</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">startOnLoad</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">securityLevel</span><span class="token operator">:</span> <span class="token string">&quot;strict&quot;</span><span class="token punctuation">,</span> <span class="token literal-property property">theme</span><span class="token operator">:</span> <span class="token string">&quot;neutral&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// https://github.com/mermaid-js/mermaid/blob/e6e94ad57ea06ef8627bf91ddfbd88f5082952bf/src/mermaid.js#L153</span> </span><span class="code-line"> <span class="token comment">// mermaid.contentLoaded();</span> </span><span class="code-line"> mermaid<span class="token punctuation">.</span><span class="token property-access function method">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token class-name console">console</span><span class="token punctuation">.</span><span class="token property-access function method">log</span><span class="token punctuation">(</span><span class="token string">&quot;mermaid init done&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access function method">addEventListener</span><span class="token punctuation">(</span><span class="token string">&#x27;load&#x27;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// load mermaid</span> </span><span class="code-line"> <span class="token function">loadMermaidOnNeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>如果要调试问题,可以在配置里增加 <code>logLevel: 1,</code></p><p><code>theme: &quot;neutral&quot;</code> 是指定主题,可以从 <code>default, dark, neutral, forest</code> 四个里面选。 如果不太满意默认的,也可以自行 DIY, 参考 <a href="https://mermaid-js.github.io/mermaid/#/theming">https://mermaid-js.github.io/mermaid/#/theming</a></p><p><code>startOnLoad</code> 选项其实在我们这里并没有什么用。 如果调用 <code>mermaid.contentLoaded()</code> 渲染的话,需要设置 <code>startOnLoad</code> 为 <code>true</code>. 但是其实 <code>contentLoaded</code> 就是判断了一下 <code>startOnLoad</code> 然后调用了 <code>mermaid.init()</code>, 因此这里老灯直接调用 <code>mermaid.init()</code> 渲染了。</p><p>最后,偷懒的可以直接用老灯这个修改版的<code>terminal</code>主题 <a href="https://github.com/ttys3/hugo-theme-terminal/tree/ttys3">https://github.com/ttys3/hugo-theme-terminal/tree/ttys3</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://code.luasoftware.com/tutorials/hugo/how-to-escape-shortcode-in-hugo/">https://code.luasoftware.com/tutorials/hugo/how-to-escape-shortcode-in-hugo/</a></p><p><a href="https://github.com/mermaid-js/mermaid">https://github.com/mermaid-js/mermaid</a></p><p><a href="https://github.com/mermaid-js/mermaid-live-editor">https://github.com/mermaid-js/mermaid-live-editor</a></p><p><a href="https://github.com/matcornic/hugo-theme-learn">https://github.com/matcornic/hugo-theme-learn</a></p><p><a href="https://github.com/matcornic/hugo-theme-learn/blob/master/layouts/shortcodes/mermaid.html">https://github.com/matcornic/hugo-theme-learn/blob/master/layouts/shortcodes/mermaid.html</a></p><p><a href="https://mermaid-js.github.io/mermaid/#/Setup?id=startonload">https://mermaid-js.github.io/mermaid/#/Setup?id=startonload</a></p><p><a href="https://mermaid-js.github.io/mermaid/#/Setup?id=securitylevel">https://mermaid-js.github.io/mermaid/#/Setup?id=securitylevel</a></p><p>strict: (default) tags in text are encoded, click functionality is disabeled loose: tags in text are allowed, click functionality is enabled antiscript: html tags in text are allowed, (only script element is removed), click functionality is enabled</p> Sat, 05 Jun 2021 16:27:41 GMT ttyS3 mermaidhugoshortcodeflowchart https://ttys3.dev/blog/got-my-hugo-permalink-config-adjusted 调整了下 Hugo 永久链接生成配置 https://ttys3.dev/blog/got-my-hugo-permalink-config-adjusted <p>之前一直用的是 Hugo 默认的 permalink 配置.</p><p>如 <code>content/post/linux/commandlinefu/how-to-start-tmux-as-systemd-user-service/index.md</code> 将会生成<br/><code>/post/linux/commandlinefu/how-to-start-tmux-as-systemd-user-service/</code> 的 URL path.</p><p>最近我越来越发现这样的链接过度复杂了,干脆直接调整成 <code>/post/:filename/</code> 。</p><p>于是 <code>/post/linux/commandlinefu/how-to-start-tmux-as-systemd-user-service/</code> 变成了 <code>/post/how-to-start-tmux-as-systemd-user-service/</code> 。</p><p>这意味着,目录结构可能不单是我组织文件的方式,同时也被用来分类了 (<code>父类/子类/文章slug</code>)。</p><p>这给我带来了负担,导致我很久都没写博客。因为有时候想写点东西,又纠结,应该放在哪个分类下面。</p><p>因为有些东西是很难划分界线的,可能属于这个分类,但是你放在另一个分类里,也不是不可以。</p><p>从 URL 里去掉可以肉眼看出是分类的部分 path, 同时,彻底去掉分类这个东西。用 tags 来分类。 一个文章可以有很多 tags , 手动写几个 tags 来给文章分类即可。</p><p>想想以前用 WordPress 的时候,我甚至用过4级分类,现在想来,那时候真是疯了。</p><p>调整配置之后,page bunlde 的图片无法显示了。于是修复了下,就不细说了,直接贴一下我的 commit log.</p><div class="relative"><pre><code class="language-diff code-highlight"><span class="code-line">commit 4ddd32088bba8486b2aa72a29c0ac0f540de9bd4 </span><span class="code-line">Author: 荒野無燈 </span><span class="code-line">Date: Wed Jun 2 23:26:08 2021 +0800 </span><span class="code-line"> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> fix(url): fixup rel page bundle image resource url for permalinks config set to /post/:filename/ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> for example: </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> for url `http://localhost:1313/post/tmux-24bit-true-color-support/` </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> the real page bundle path is `content/post/linux/apps/tmux-24bit-true-color-support` </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> since our permalink config is set to `:filename`, so the real image for the page bundle </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> will copied to `public/post/tmux-24bit-true-color-support` </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> so the `RelPermalink` (directory created according to permalinks config) decided the image&#x27;s directory. </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> even if we changed the permalinks config to /post/:slug or other format, the code will works fine </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line">diff --git a/layouts/_default/_markup/render-image.html b/layouts/_default/_markup/render-image.html </span><span class="code-line">index 26c4bc3..0c5036b 100644 </span><span class="code-line deleted"><span class="token coord">--- a/layouts/_default/_markup/render-image.html</span> </span><span class="code-line inserted"><span class="token coord">+++ b/layouts/_default/_markup/render-image.html</span> </span><span class="code-line"><span class="token coord">@@ -5,7 +5,7 @@</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">{{/* process relative PATH URL in page bundle: no Scheme and not start with `/` */}} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">{{ if and (eq $theURL.Scheme &quot;&quot;) (not (strings.HasPrefix .Destination &quot;/&quot;)) }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ if eq &quot;index.md&quot; .Page.File.LogicalName }} </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> {{ $imgSrc = printf &quot;%s/%s&quot; .Page.File.Dir .Destination | absURL | safeURL }} </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> {{ $imgSrc = printf &quot;%s/%s&quot; .Page.RelPermalink .Destination | absURL | safeURL }} </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> {{ end }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">{{ end }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>diff --git a/layouts/_default/_markup/render-image.rss.xml b/layouts/_default/_markup/render-image.rss.xml </span><span class="code-line">index 48846b9..3cffcd4 100644 </span><span class="code-line deleted"><span class="token coord">--- a/layouts/_default/_markup/render-image.rss.xml</span> </span><span class="code-line inserted"><span class="token coord">+++ b/layouts/_default/_markup/render-image.rss.xml</span> </span><span class="code-line"><span class="token coord">@@ -5,7 +5,7 @@</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">{{/* process relative PATH URL in page bundle: no Scheme and not start with `/` */}} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">{{ if and (eq $theURL.Scheme &quot;&quot;) (not (strings.HasPrefix .Destination &quot;/&quot;)) }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ if eq &quot;index.md&quot; .Page.File.LogicalName }} </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> {{ $imgSrc = printf &quot;%s/%s&quot; .Page.File.Dir .Destination | absURL | safeURL }} </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> {{ $imgSrc = printf &quot;%s/%s&quot; .Page.RelPermalink .Destination | absURL | safeURL }} </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> {{ end }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">{{ end }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>diff --git a/layouts/_default/_markup/render-link.html b/layouts/_default/_markup/render-link.html </span><span class="code-line">index a101673..ae92493 100644 </span><span class="code-line deleted"><span class="token coord">--- a/layouts/_default/_markup/render-link.html</span> </span><span class="code-line inserted"><span class="token coord">+++ b/layouts/_default/_markup/render-link.html</span> </span><span class="code-line"><span class="token coord">@@ -7,7 +7,7 @@</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">{{/* process relative PATH URL in page bundle: no Scheme and not start with `/` */}} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">{{ if and (eq $theURL.Scheme &quot;&quot;) (not (strings.HasPrefix .Destination &quot;/&quot;)) }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ if eq &quot;index.md&quot; .Page.File.LogicalName }} </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> {{ $linkHref = printf &quot;%s/%s&quot; .Page.File.Dir .Destination | absURL | safeURL }} </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> {{ $linkHref = printf &quot;%s/%s&quot; .Page.RelPermalink .Destination | absURL | safeURL }} </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> {{ end }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">{{ end }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>diff --git a/layouts/_default/list.html b/layouts/_default/list.html </span><span class="code-line">index cceef21..f2b89c0 100644 </span><span class="code-line deleted"><span class="token coord">--- a/layouts/_default/list.html</span> </span><span class="code-line inserted"><span class="token coord">+++ b/layouts/_default/list.html</span> </span><span class="code-line"><span class="token coord">@@ -41,7 +41,7 @@</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ if .Params.cover }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ if eq &quot;index.md&quot; .File.LogicalName }} </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> &lt;img src=&quot;{{ printf &quot;%s/%s&quot; .File.Dir .Params.cover | absURL }}&quot; class=&quot;post-cover&quot; /&gt; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> &lt;img src=&quot;{{ printf &quot;%s/%s&quot; .RelPermalink .Params.cover | absURL }}&quot; class=&quot;post-cover&quot; /&gt; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> {{ else }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;img src=&quot;{{ .Params.cover | absURL }}&quot; class=&quot;post-cover&quot; /&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ end }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>diff --git a/layouts/_default/single.html b/layouts/_default/single.html </span><span class="code-line">index a2ae357..72354bc 100644 </span><span class="code-line deleted"><span class="token coord">--- a/layouts/_default/single.html</span> </span><span class="code-line inserted"><span class="token coord">+++ b/layouts/_default/single.html</span> </span><span class="code-line"><span class="token coord">@@ -35,7 +35,7 @@</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ if .Params.cover }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ if eq &quot;index.md&quot; .File.LogicalName }} </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> &lt;img src=&quot;{{ printf &quot;%s/%s&quot; .File.Dir .Params.cover | absURL }}&quot; class=&quot;post-cover&quot; /&gt; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> &lt;img src=&quot;{{ printf &quot;%s/%s&quot; .RelPermalink .Params.cover | absURL }}&quot; class=&quot;post-cover&quot; /&gt; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> {{ else }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &lt;img src=&quot;{{ .Params.cover | absURL }}&quot; class=&quot;post-cover&quot; /&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> {{ end }} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span></code></pre></div> Thu, 03 Jun 2021 20:32:36 GMT ttyS3 hugopermalinkconfig https://ttys3.dev/blog/how-to-update-hugo-blog-algolia-index Hugo 博客如何更新 Algolia 索引 https://ttys3.dev/blog/how-to-update-hugo-blog-algolia-index <p>集成 Algolia 后,最简单无脑的更新索引方式就是每次构建后由 Netlify 触发 webhook 通知 Algolia 自动抓取。 这也就是 Algolia Crawler for Netlify 干的活。</p><p>但是老灯使用一段时间后发现存在一些问题:</p><ol><li>每发一篇博客,甚至可能是只改动了一个字就要触发全量索引 (git push 触发了 Netlify CI CD -&gt; webhook -&gt; Algolia Crawler 干活 -&gt; 抓取全站 URL 并索引)。一是浪费资源,二是低低效(速度慢)。</li><li>很多不需要索引的页面也被索引进去了,比如 tags 和 categories 的分页列表页面。我博客总共才70篇文章不到,索引后的页面居然有300多!</li></ol><p>要个性化的索引,还得自己动手。毕竟你自己的内容,自己最清楚。</p><p>浏览了下 Github, star 数量多的相关项目几乎没有。</p><p><a href="https://github.com/spotlightpa/algolia-indexer">https://github.com/spotlightpa/algolia-indexer</a> 0 star</p><p><a href="https://github.com/duckpuppy/algolia-hugo">https://github.com/duckpuppy/algolia-hugo</a> 8 star 但是我稍看了下代码,觉得他把简单的事情搞复杂了,还用到了 viper 这个 go mod, 天啊,放弃吧。</p><p>继续找,找到一个 <a href="https://github.com/naah69/Hugo-Algolia-Chinese-Builder">https://github.com/naah69/Hugo-Algolia-Chinese-Builder</a> 但是,这个 repo 的命名首先就很不 golang style.</p><p>于是我 fork 出来新的 <a href="https://github.com/ttys3/hugo-algolia-updater">https://github.com/ttys3/hugo-algolia-updater</a> 并整理了一下代码。</p><p>加上 golangci-lint 和 zap logger. 最终效果如图:</p><div><img alt="" src="https://ttys3.dev/static/assets/hugo-algolia-updater-2021-06-04_04-16-FTMIVV3N.png" width="1799" height="1407"/></div><p>代码还有待优化,时间有限,先这样了。</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://www.algolia.com/doc/tools/crawler/netlify-plugin/quick-start/">https://www.algolia.com/doc/tools/crawler/netlify-plugin/quick-start/</a></p><p><a href="https://www.netlify.com/blog/2017/10/10/replacing-our-search-with-algolia/">https://www.netlify.com/blog/2017/10/10/replacing-our-search-with-algolia/</a></p> Thu, 03 Jun 2021 19:48:36 GMT ttyS3 hugosearchindexupdater https://ttys3.dev/blog/pacman-6-0-released Pacman 6.0 发布 https://ttys3.dev/blog/pacman-6-0-released <p>最近升级到了 pacman 6.0 版本。主要的新功能是支持多线程下载了。</p><p>如果是从旧版本升级的,那么其实配置需要自己手动合并。简单来说就是添加一行</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line"><span class="token attr-name key">ParallelDownloads</span> <span class="token punctuation">=</span> <span class="token attr-value value">5</span> </span></code></pre></div><p>即可。</p><p>虽然将下载器配置成aria2 或 curl (新版本的curl 有多线程下载功能 -Z ) 也能实现多线程下载,但是终究还是不如官方直接支持香。</p><p>贴下我的完整配置 <code>/etc/pacman.conf</code> :</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># /etc/pacman.conf</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># See the pacman.conf(5) manpage for option and repository directives</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># GENERAL OPTIONS</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">options</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token comment"># The following paths are commented out with their default values listed.</span> </span><span class="code-line"><span class="token comment"># If you wish to use different paths, uncomment and update the paths.</span> </span><span class="code-line"><span class="token comment">#RootDir = /</span> </span><span class="code-line"><span class="token comment">#DBPath = /var/lib/pacman/</span> </span><span class="code-line"><span class="token comment">#CacheDir = /var/cache/pacman/pkg/</span> </span><span class="code-line"><span class="token comment">#LogFile = /var/log/pacman.log</span> </span><span class="code-line"><span class="token comment">#GPGDir = /etc/pacman.d/gnupg/</span> </span><span class="code-line"><span class="token comment">#HookDir = /etc/pacman.d/hooks/</span> </span><span class="code-line"><span class="token attr-name key">HoldPkg</span> <span class="token punctuation">=</span> <span class="token attr-value value">pacman glibc</span> </span><span class="code-line"><span class="token comment">#XferCommand = /usr/bin/curl -L -C - -f -o %o %u</span> </span><span class="code-line"><span class="token comment">#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u</span> </span><span class="code-line"><span class="token comment">#CleanMethod = KeepInstalled</span> </span><span class="code-line"><span class="token attr-name key">Architecture</span> <span class="token punctuation">=</span> <span class="token attr-value value">auto</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Pacman won&#x27;t upgrade packages listed in IgnorePkg and members of IgnoreGroup</span> </span><span class="code-line"><span class="token comment">#IgnorePkg = tree-sitter</span> </span><span class="code-line"><span class="token comment">#IgnoreGroup =</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#NoUpgrade =</span> </span><span class="code-line"><span class="token comment">#NoExtract =</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Misc options</span> </span><span class="code-line"><span class="token comment">#UseSyslog</span> </span><span class="code-line">Color </span><span class="code-line"><span class="token comment">#NoProgressBar</span> </span><span class="code-line">CheckSpace </span><span class="code-line">VerbosePkgLists </span><span class="code-line"><span class="token attr-name key">ParallelDownloads</span> <span class="token punctuation">=</span> <span class="token attr-value value">5</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># By default, pacman accepts packages signed by keys that its local keyring</span> </span><span class="code-line"><span class="token comment"># trusts (see pacman-key and its man page), as well as unsigned packages.</span> </span><span class="code-line"><span class="token attr-name key">SigLevel</span> <span class="token punctuation">=</span> <span class="token attr-value value">Required DatabaseOptional</span> </span><span class="code-line"><span class="token attr-name key">LocalFileSigLevel</span> <span class="token punctuation">=</span> <span class="token attr-value value">Optional</span> </span><span class="code-line"><span class="token comment">#RemoteFileSigLevel = Required</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># NOTE: You must run `pacman-key --init` before first using pacman; the local</span> </span><span class="code-line"><span class="token comment"># keyring can then be populated with the keys of all official Arch Linux</span> </span><span class="code-line"><span class="token comment"># packagers with `pacman-key --populate archlinux`.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># REPOSITORIES</span> </span><span class="code-line"><span class="token comment"># - can be defined here or included from another file</span> </span><span class="code-line"><span class="token comment"># - pacman will search repositories in the order defined here</span> </span><span class="code-line"><span class="token comment"># - local/custom mirrors can be added here or in separate files</span> </span><span class="code-line"><span class="token comment"># - repositories listed first will take precedence when packages</span> </span><span class="code-line"><span class="token comment"># have identical names, regardless of version number</span> </span><span class="code-line"><span class="token comment"># - URLs will have $repo replaced by the name of the current repo</span> </span><span class="code-line"><span class="token comment"># - URLs will have $arch replaced by the name of the architecture</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># Repository entries are of the format:</span> </span><span class="code-line"><span class="token comment"># [repo-name]</span> </span><span class="code-line"><span class="token comment"># Server = ServerName</span> </span><span class="code-line"><span class="token comment"># Include = IncludePath</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># The header [repo-name] is crucial - it must be present and</span> </span><span class="code-line"><span class="token comment"># uncommented to enable the repo.</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># The testing repositories are disabled by default. To enable, uncomment the</span> </span><span class="code-line"><span class="token comment"># repo name header and Include lines. You can add preferred servers immediately</span> </span><span class="code-line"><span class="token comment"># after the header, and they will be used before the default mirrors.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#[testing]</span> </span><span class="code-line"><span class="token comment">#Include = /etc/pacman.d/mirrorlist</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">core</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Include</span> <span class="token punctuation">=</span> <span class="token attr-value value">/etc/pacman.d/mirrorlist</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">extra</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Include</span> <span class="token punctuation">=</span> <span class="token attr-value value">/etc/pacman.d/mirrorlist</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#[community-testing]</span> </span><span class="code-line"><span class="token comment">#Include = /etc/pacman.d/mirrorlist</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">community</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Include</span> <span class="token punctuation">=</span> <span class="token attr-value value">/etc/pacman.d/mirrorlist</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># If you want to run 32 bit applications on your x86_64 system,</span> </span><span class="code-line"><span class="token comment"># enable the multilib repositories as required here.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#[multilib-testing]</span> </span><span class="code-line"><span class="token comment">#Include = /etc/pacman.d/mirrorlist</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#[multilib]</span> </span><span class="code-line"><span class="token comment">#Include = /etc/pacman.d/mirrorlist</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># An example of a custom package repository. See the pacman manpage for</span> </span><span class="code-line"><span class="token comment"># tips on creating your own repositories.</span> </span><span class="code-line"><span class="token comment">#[custom]</span> </span><span class="code-line"><span class="token comment">#SigLevel = Optional TrustAll</span> </span><span class="code-line"><span class="token comment">#Server = file:///home/custompkgs</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">## 中国科学技术大学 (安徽合肥) (ipv4, ipv6, http, https)</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">archlinuxcn</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.sjtug.sjtu.edu.cn/archlinux-cn/$arch</span> </span></code></pre></div><p>对应的, aur helper 工具 <code>paru</code> 最近也升级到 v1.7.1 了。</p><p><code>/etc/paru.conf</code> 配置:</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># $PARU_CONF</span> </span><span class="code-line"><span class="token comment"># /etc/paru.conf</span> </span><span class="code-line"><span class="token comment"># ~/.config/paru/paru.conf</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># See the paru.conf(5) manpage for options</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># GENERAL OPTIONS</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">options</span><span class="token punctuation">]</span></span> </span><span class="code-line">PgpFetch </span><span class="code-line">Devel </span><span class="code-line">Provides </span><span class="code-line"><span class="token attr-name key">DevelSuffixes</span> <span class="token punctuation">=</span> <span class="token attr-value value">-git -cvs -svn -bzr -darcs -always</span> </span><span class="code-line"><span class="token comment">#BottomUp</span> </span><span class="code-line"><span class="token comment">#RemoveMake</span> </span><span class="code-line"><span class="token comment">#SudoLoop</span> </span><span class="code-line"><span class="token comment">#UseAsk</span> </span><span class="code-line"><span class="token comment">#CombinedUpgrade</span> </span><span class="code-line"><span class="token comment">#CleanAfter</span> </span><span class="code-line"><span class="token comment">#UpgradeMenu</span> </span><span class="code-line"><span class="token comment">#NewsOnUpgrade</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#LocalRepo</span> </span><span class="code-line"><span class="token comment">#Chroot</span> </span><span class="code-line"><span class="token comment">#MovePkgs</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># Binary OPTIONS</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">bin</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">FileManager</span> <span class="token punctuation">=</span> <span class="token attr-value value">vifm</span> </span><span class="code-line"><span class="token comment">#MFlags = --skippgpcheck</span> </span><span class="code-line"><span class="token comment">#Sudo = doas</span> </span></code></pre></div> Thu, 03 Jun 2021 19:36:18 GMT ttyS3 parupacmanarchlinux https://ttys3.dev/blog/gpg-signing-failed-inappropriate-ioctl-for-device gpg: signing failed: Inappropriate ioctl for device 解决办法 https://ttys3.dev/blog/gpg-signing-failed-inappropriate-ioctl-for-device <p>最近换了系统, git commit 在gpg签名的时候出错了:</p><blockquote><p>gpg: signing failed: Inappropriate ioctl for device</p></blockquote><p>原因是 gpg 在当前终端无法弹出密码输入页面。</p><p>解决办法:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">GPG_TTY</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">tty</span><span class="token variable">)</span></span> </span></code></pre></div><p>重新执行,发现会弹出一个密码输入界面。</p><p>参考: <a href="https://www.jianshu.com/p/2ed292ae2365">https://www.jianshu.com/p/2ed292ae2365</a></p><p>但是老灯觉得这不是解决办法,因为在此之前,我从来没遇到过这个问题。产生这个问题是有原因的。</p><p>于是再去看了一下Arch的文档,果然,有说明“Invalid IPC response and Inappropriate ioctl for device” 这个问题。虽然报错语句不一样,但是其实是一个问题。</p><p><a href="https://wiki.archlinux.org/title/GnuPG#Invalid_IPC_response_and_Inappropriate_ioctl_for_device">https://wiki.archlinux.org/title/GnuPG#Invalid_IPC_response_and_Inappropriate_ioctl_for_device</a></p><p>The default pinentry program is <code>/usr/bin/pinentry-gtk-2</code>. If <code>gtk2</code> is unavailable, <code>pinentry</code> falls back to <code>/usr/bin/pinentry-curses</code> and causes signing to fail:</p><p>gpg: signing failed: Inappropriate ioctl for device gpg: [stdin]: clear-sign failed: Inappropriate ioctl for device You need to set the <code>GPG_TTY</code> environment variable for the <code>pinentry</code> programs /usr/bin/pinentry-tty and /usr/bin/pinentry-curses.</p><p><span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi><mi>x</mi><mi>p</mi><mi>o</mi><mi>r</mi><mi>t</mi><mi>G</mi><mi>P</mi><msub><mi>G</mi><mi>T</mi></msub><mi>T</mi><mi>Y</mi><mo>=</mo></mrow><annotation encoding="application/x-tex"> export GPG_TTY=</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:.8778em;vertical-align:-.1944em"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:.02778em">or</span><span class="mord mathnormal" style="margin-right:.13889em">tGP</span><span class="mord"><span class="mord mathnormal">G</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:.3283em"><span style="top:-2.55em;margin-left:0;margin-right:.05em"><span class="pstrut" style="height:2.7em"></span><span class="mtight reset-size6 size3 sizing"><span class="mord mathnormal mtight" style="margin-right:.13889em">T</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:.15em"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:.13889em">T</span><span class="mord mathnormal" style="margin-right:.22222em">Y</span><span class="mspace" style="margin-right:.2778em"></span><span class="mrel">=</span></span></span></span></span>(tty)</p><p>如果我们看一下 <code>/usr/bin/pinentry</code> 这个shell脚本, 内容如下:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token important shebang">#!/bin/sh</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># user-defined pre-exec hook</span> </span><span class="code-line"><span class="token builtin class-name">test</span> <span class="token variable parameter">-r</span> <span class="token string">&quot;<span class="token variable">${XDG_CONFIG_HOME<span class="token operator">:-</span>$HOME<span class="token operator">/</span>.config}</span>&quot;</span>/pinentry/preexec <span class="token operator">&amp;&amp;</span> </span><span class="code-line"> <span class="token builtin class-name">.</span> <span class="token string">&quot;<span class="token variable">${XDG_CONFIG_HOME<span class="token operator">:-</span>$HOME<span class="token operator">/</span>.config}</span>&quot;</span>/pinentry/preexec </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># site-defined pre-exec hook</span> </span><span class="code-line"><span class="token builtin class-name">test</span> <span class="token variable parameter">-r</span> /etc/pinentry/preexec <span class="token operator">&amp;&amp;</span> </span><span class="code-line"> <span class="token builtin class-name">.</span> /etc/pinentry/preexec </span><span class="code-line"> </span><span class="code-line"><span class="token builtin class-name">test</span> <span class="token variable parameter">-e</span> /usr/lib/libgtk-x11-2.0.so.0 <span class="token operator">&amp;&amp;</span> </span><span class="code-line"> <span class="token builtin class-name">exec</span> /usr/bin/pinentry-gtk-2 <span class="token string">&quot;<span class="token variable">$@</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token builtin class-name">exec</span> /usr/bin/pinentry-curses <span class="token string">&quot;<span class="token variable">$@</span>&quot;</span> </span></code></pre></div><p>然后我们看看 /etc/pinentry/preexec 的内容,发现 <code>/usr/bin/pinentry-gnome3</code> 和 <code>/usr/bin/pinentry-qt</code> 其实在我当前系统上都是存在的,所以,最简单的办法,其实我们注释掉<code>pinentry-gnome3</code> 那一行,或qt那一行都OK.</p><p>这样就没有必要再fallback 到 pinentry-gtk-2 或 pinentry-curses 了</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token important shebang">#!/hint/sh</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Define additional functionality for pinentry. For example</span> </span><span class="code-line"><span class="token comment">#test -e /usr/lib/libgcr-base-3.so.1 &amp;&amp; exec /usr/bin/pinentry-gnome3 &quot;$@&quot;</span> </span><span class="code-line"><span class="token comment">#test -e /usr/lib/libQt5Widgets.so.5 &amp;&amp; exec /usr/bin/pinentry-qt &quot;$@&quot;</span> </span></code></pre></div><p>根据 Arch 文档, “<em>gpg-agent</em> is mostly used as daemon to request and cache the password for the keychain. ”, 我们使用ssh的时候,有ssh-agent 或类似 gnome seahorse 之类的工具充当agent, 那么 gpg 其实也有 agent的,这个 agent 一定是属于当前用户的,如果遇到问题,不防检查一下它是不是正确运行状态,当然,老灯这次遇到的并不是这个问题, gpg-agent 运行正常:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">  ~ </span><span class="code-line">❯ systemctl <span class="token variable parameter">--user</span> status gpg-agent.socket </span><span class="code-line">● gpg-agent.socket - GnuPG cryptographic agent and passphrase cache </span><span class="code-line"> Loaded: loaded <span class="token punctuation">(</span>/usr/lib/systemd/user/gpg-agent.socket<span class="token punctuation">;</span> enabled<span class="token punctuation">;</span> vendor preset: enabled<span class="token punctuation">)</span> </span><span class="code-line"> Active: active <span class="token punctuation">(</span>running<span class="token punctuation">)</span> since Wed <span class="token number">2021</span>-05-05 09:54:33 CST<span class="token punctuation">;</span> 12h ago </span><span class="code-line"> Triggers: ● gpg-agent.service </span><span class="code-line"> Docs: man:gpg-agent<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> </span><span class="code-line"> Listen: /run/user/1000/gnupg/S.gpg-agent <span class="token punctuation">(</span>Stream<span class="token punctuation">)</span> </span><span class="code-line"> CGroup: /user.slice/user-1000.slice/[email protected]/app.slice/gpg-agent.socket </span><span class="code-line"> </span><span class="code-line">May 05 09:54:33 wudeng systemd<span class="token punctuation">[</span><span class="token number">1297</span><span class="token punctuation">]</span>: Listening on GnuPG cryptographic agent and passphrase cache. </span></code></pre></div> Wed, 05 May 2021 14:05:12 GMT ttyS3 gpggitpinentrytty https://ttys3.dev/blog/paru-the-new-aur-helper Paru -- The New AUR Helper https://ttys3.dev/blog/paru-the-new-aur-helper <h2 id="paru-是什么"><a href="#paru-是什么" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>paru 是什么?</h2><p>根据 <a href="https://www.reddit.com/r/archlinux/comments/jjn1c1/paru_v100_and_stepping_away_from_yay/">paru 作者在 reddit 的描述</a></p><blockquote><p>paru v1.0.0 and stepping away from yay</p><p>Last week I announced my new AUR helper paru.</p><p>Since then a lot of testing has gone in and a lot of bugs fixed by me and help from contributors.</p><p>So I am now announcing paru v1.0.0 and consider it stable.</p><p>I&#x27;d also like to mention <strong>I no longer plan to work on yay</strong>. I&#x27;ve been <strong>co-developing yay</strong> with jguer over the past 3 years. Most of the features and design being done by me.</p><p>I&#x27;ve had no motivation and no real involvement with the project for quite a while now. So I&#x27;m officially deciding to move on to something new.</p><p><strong>Jguer is still there</strong>, so there&#x27;s no need to panic and move away from yay. Just don&#x27;t expect much new development on it.</p></blockquote><p>所以, parau 的作者之前也是yay的共同开发者。yay 是采用 Golang 编写的 AUR helper, 而新的 paru 采用 Rust 实现。</p><h2 id="changes-from-yay"><a href="#changes-from-yay" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>changes from yay</h2><p>paru 首个版本发布时,作者在release log 里描述了它与 yay 的区别。</p><h4 id="added"><a href="#added" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Added</h4><ul><li>Added --nocheck</li><li>Added --develsuffixes</li><li>Added --installDebug</li><li>Added NoWarn</li><li>Added syntax highlighting to pkgbuild printing</li><li>Auto detection for pacman-git. Paru will build against pacman-git&#x27;s API</li></ul><h4 id="removed"><a href="#removed" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Removed</h4><ul><li>Remove --timeupdate, --requestsplitn</li><li>Remove --save -Pg --Pd -Ps</li><li>Remove -Gf</li><li>Remove --cleanmenu</li><li>Remove -Y/--yay, stuff like --gendb still work even though they belonged to -Y</li></ul><h4 id="changed"><a href="#changed" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Changed</h4><ul><li>List based flags now append instead of overwriting existing settings</li><li>Packages are now cloned to ~/.cache/paru/clone by default</li><li>Use asp for repo pkgbuilds</li><li>Improve news printing</li><li>Formatting changes to be more pacman like</li><li>-Yc accounts for makedeps for aur packages</li><li>Devel info is now saved to devel.json</li><li>Devel info schema change</li><li>Sources are no longer downloaded in batch</li><li>Only treat packages matching develsuffixes as devel</li></ul><h2 id="如何安装paru"><a href="#如何安装paru" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何安装paru</h2><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token comment"># archlinux cn repo users</span> </span><span class="code-line"><span class="token function">sudo</span> pacman <span class="token parameter variable">-S</span> paru </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># other users</span> </span><span class="code-line"><span class="token function">sudo</span> pacman <span class="token parameter variable">-S</span> <span class="token parameter variable">--needed</span> base-devel </span><span class="code-line"><span class="token function">git</span> clone https://aur.archlinux.org/paru.git </span><span class="code-line"><span class="token class-name builtin">cd</span> paru </span><span class="code-line">makepkg <span class="token parameter variable">-si</span> </span></code></pre></div><h2 id="paru常用操作"><a href="#paru常用操作" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>paru常用操作</h2><ul><li><code>paru</code> : 相当于 <code>paru -Syu</code> (If no arguments are provided &#x27;paru -Syu&#x27; will be performed)</li><li><code>paru &lt;用户输入&gt;</code>:搜索并安装“用户输入”</li><li><code>paru -Sua</code>:仅升级 AUR 包。</li><li><code>paru -Qua</code>:打印可用的 AUR 更新</li><li><code>paru -Gc &lt;用户输入&gt;</code>:显示“用户输入”的 AUR 评论</li></ul><h2 id="paru-配置"><a href="#paru-配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>paru 配置</h2><p>要在 <code>paru</code> 中启用颜色,你必须先在 <code>pacman</code> 中启用它。编辑 <code>/etc/pacman.conf</code> ,确保 <code>Color</code> 选项是打开的即可 (老灯发现其实默认是打开的)。</p><p>paru的配置文件位于 <code>/etc/paru.conf</code></p><p>paru 有个叫 <code>BottomUp</code> 的选项,打开之后,包的显示顺序会倒过来(比如原来排名第一的,会显示在最底部),这样做的理由是:优先级较高的包,通过倒序显示后,离 Prompt 最近了,也就是离我们视线的关注点最近了。</p><p>这个喜好与否,因人而异中以。</p><p>如果需要编辑 <code>PKGBUILD</code>,需要打开parau配置文件中的 <code>FileManager</code> 选项。安装 vifm : <code>sudo pacman -S vifm</code></p><p>然后配置:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">bin</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">FileManager</span> <span class="token punctuation">=</span> vifm </span></code></pre></div><p>老灯觉得这个配置项有点奇怪。</p><p>另外一点,与yay不同的是,对于 paru, <strong>你所做的任何改变都将是永久性的,下次升级软件包时,你的改变将与上游软件包合并。</strong></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://github.com/Morganamilo/paru">https://github.com/Morganamilo/paru</a></p><p><a href="https://aur.archlinux.org/packages/paru/">https://aur.archlinux.org/packages/paru/</a></p><p><a href="https://github.com/Morganamilo/paru/releases/tag/v1.0.0">https://github.com/Morganamilo/paru/releases/tag/v1.0.0</a></p><p><a href="https://www.reddit.com/r/archlinux/comments/jjn1c1/paru_v100_and_stepping_away_from_yay/">https://www.reddit.com/r/archlinux/comments/jjn1c1/paru_v100_and_stepping_away_from_yay/</a></p><p><a href="https://www.reddit.com/r/archlinux/comments/jdyvyr/so_i_made_another_aur_helper_paru/">https://www.reddit.com/r/archlinux/comments/jdyvyr/so_i_made_another_aur_helper_paru/</a></p><p><a href="https://www.reddit.com/r/archlinux/comments/ju50j7/why_do_people_still_use_yay_instead_of_paru/">https://www.reddit.com/r/archlinux/comments/ju50j7/why_do_people_still_use_yay_instead_of_paru/</a></p><p><a href="https://linux.cn/article-13122-1.html">https://linux.cn/article-13122-1.html</a></p><p><a href="https://itsfoss.com/paru-aur-helper/">https://itsfoss.com/paru-aur-helper/</a></p> Mon, 05 Apr 2021 16:54:53 GMT ttyS3 archlinuxparuauryay https://ttys3.dev/blog/build-static-lib-package-under-archlinux Build Static Lib Package Under ArchLinux https://ttys3.dev/blog/build-static-lib-package-under-archlinux <p>通常情况下,Arch 下的包不像 RHEL 系那样有单独的静态库 (RHEL系命名风格一般是 <code>libXXX-static</code>),但并不是说Arch下面的包都没有静态库,这个得看情况。比如 /lib/libresolv.a, /lib/librt.a 属于 GNU libc (<code>glibc</code>包), /lib/libstdc++.a 属于 <code>gcc</code> 包。</p><p>以 <code>libgit2</code> 包为例,ArchLinux 源里是没有提供静态库的。相对的, Ubuntu 有提供静态库的 package, 甚至连 ArlpineLinux <a href="https://pkgs.alpinelinux.org/package/edge/community/x86_64/libgit2-static">也有提供</a>。 Fedora 下的 libgit2 好像没有静态lib。Ubuntu 是直接放在<a href="https://packages.ubuntu.com/focal/amd64/libgit2-dev/filelist"> libgit2-dev 包里</a> (/usr/lib/x86_64-linux-gnu/libgit2.a)</p><p>由于Arch源里其实已经有libgit2了,因此我们对 <code>PKGBUILD </code>文件作做修改即可编译相应的静态库。</p><p>首先我们安装 asp, 如果没有安装的话: <code>sudo pacman -S --needed asp</code></p><p>然后获取Arch构建源码: <code>asp checkout libgit2</code></p><p>修改之后执行 <code>makepkg</code> 即可。</p><p>如果不用asp, 也可以手动用git clone源码。</p><p>进入包页面 <a href="https://archlinux.org/packages/extra/x86_64/libgit2/">https://archlinux.org/packages/extra/x86_64/libgit2/</a> 然后 点击 <strong>Source Files</strong> 即可查看源码。然后我们就跳到了 <a href="https://github.com/archlinux/svntogit-packages/tree/packages/libgit2/trunk">https://github.com/archlinux/svntogit-packages/tree/packages/libgit2/trunk</a></p><p>clone仓库然后 checkout 到 <code>packages/libgit2/trunk</code> 分支即可。(对于 Arch 这种用分支来存包源码的行为,老灯表示有点迷啊,可能跟它从svn转过来有关?)</p><p>原 <code>PKGBUILD</code> 文件如下:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># Maintainer: Lukas Fleischer &lt;[email protected]&gt;</span> </span><span class="code-line"><span class="token comment"># Contributor: David Runge &lt;[email protected]&gt;</span> </span><span class="code-line"><span class="token comment"># Contributor: Hilton Medeiros &lt;[email protected]&gt;</span> </span><span class="code-line"><span class="token comment"># Contributor: Dave Reisner &lt;[email protected]&gt;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token variable assign-left">pkgname</span><span class="token operator">=</span>libgit2 </span><span class="code-line"><span class="token variable assign-left">pkgver</span><span class="token operator">=</span><span class="token number">1.1</span>.0 </span><span class="code-line"><span class="token variable assign-left">pkgrel</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">epoch</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">pkgdesc</span><span class="token operator">=</span><span class="token string">&#x27;A linkable library for Git&#x27;</span> </span><span class="code-line"><span class="token variable assign-left">arch</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;x86_64&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">url</span><span class="token operator">=</span><span class="token string">&quot;https://libgit2.github.com/&quot;</span> </span><span class="code-line"><span class="token variable assign-left">depends</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;glibc&#x27;</span> <span class="token string">&#x27;http-parser&#x27;</span> <span class="token string">&#x27;openssl&#x27;</span> <span class="token string">&#x27;pcre&#x27;</span> <span class="token string">&#x27;zlib&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">makedepends</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;cmake&#x27;</span> <span class="token string">&#x27;libssh2&#x27;</span> <span class="token string">&#x27;python&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">provides</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;libgit2.so&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">license</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;GPL2&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">source</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&quot;<span class="token variable">$pkgname</span>-<span class="token variable">$pkgver</span>.tar.gz::https://github.com/libgit2/libgit2/archive/v<span class="token variable">${pkgver}</span>.tar.gz&quot;</span> </span><span class="code-line"> <span class="token string">&quot;<span class="token variable">${pkgname}</span>-0.99.0-remove_http-parse_incompatible_tests.patch&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">sha512sums</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;347bb68900181b44fa58a0417506c91383adb965607fce049a5b4c57ac9cc286e0a140d164c339b50fb6cd6951f47757c2917a2df44ba004bfaa4fb643946bb8&#x27;</span> </span><span class="code-line"> <span class="token string">&#x27;e73072424c9c1870eaaf93b3451295ef7333b59f6cb8a6897dd690b69a20aaeb70f00d15a692c1d9e0745d5ef16bbbb912fbd570d8bc83ca0b7d57f32025bf94&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">b2sums</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;2a1c1f71d2a2e06448c78eb46028fdcfd59682dccf2365851c4bd059cdd78842320f9a5ba7345e761611a5b4eba634faf2e26cc669097da0ba2e1c832c23059f&#x27;</span> </span><span class="code-line"> <span class="token string">&#x27;cdca2012f772afea99436faa02f80697dc9042a6eb5ae14f8ee8ba9e100a65b936cdfaf84ec0361543c70859375c823a25cfee52b0face40b8dea2ec2cf1de59&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">prepare</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">$pkgname</span>-<span class="token variable">$pkgver</span>&quot;</span> </span><span class="code-line"> <span class="token comment"># removing tests that are only compatible with the (modified) vendored</span> </span><span class="code-line"> <span class="token comment"># version of http-parser, but not with upstream http-parser</span> </span><span class="code-line"> patch <span class="token variable parameter">-Np1</span> <span class="token variable parameter">-i</span> <span class="token string">&quot;../<span class="token variable">${pkgname}</span>-0.99.0-remove_http-parse_incompatible_tests.patch&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">$pkgname</span>-<span class="token variable">$pkgver</span>&quot;</span> </span><span class="code-line"> cmake <span class="token variable parameter">-DCMAKE_INSTALL_PREFIX</span><span class="token operator">=</span>/usr <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-DCMAKE_BUILD_TYPE</span><span class="token operator">=</span><span class="token string">&#x27;None&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-DUSE_HTTP_PARSER</span><span class="token operator">=</span>system <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-DTHREADSAFE</span><span class="token operator">=</span>ON <span class="token punctuation">\</span> </span><span class="code-line"> -Wno-dev <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-B</span> build <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-S</span> <span class="token builtin class-name">.</span> </span><span class="code-line"> <span class="token function">make</span> <span class="token variable parameter">-C</span> build <span class="token variable assign-left">VERBOSE</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">check</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">$pkgname</span>-<span class="token variable">$pkgver</span>&quot;</span> </span><span class="code-line"> <span class="token function">make</span> <span class="token variable parameter">-C</span> build <span class="token builtin class-name">test</span> <span class="token variable assign-left">VERBOSE</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">package</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token variable assign-left">depends</span><span class="token operator">+=</span><span class="token punctuation">(</span><span class="token string">&#x27;libssh2.so&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">$pkgname</span>-<span class="token variable">$pkgver</span>&quot;</span> </span><span class="code-line"> <span class="token function">make</span> <span class="token variable parameter">-C</span> build <span class="token variable assign-left">DESTDIR</span><span class="token operator">=</span><span class="token string">&quot;<span class="token variable">$pkgdir</span>&quot;</span> <span class="token function">install</span> </span><span class="code-line"> <span class="token function">install</span> <span class="token variable parameter">-vDm</span> <span class="token number">644</span> <span class="token punctuation">{</span>AUTHORS,README.md<span class="token punctuation">}</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-t</span> <span class="token string">&quot;<span class="token variable">${pkgdir}</span>/usr/share/doc/<span class="token variable">${pkgname}</span>&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>我们稍做修改:</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">diff --git a/trunk/PKGBUILD b/trunk/PKGBUILD </span><span class="code-line">index 9192069..9eb6a7a 100644 </span><span class="code-line deleted"><span class="token coord">--- a/trunk/PKGBUILD</span> </span><span class="code-line inserted"><span class="token coord">+++ b/trunk/PKGBUILD</span> </span><span class="code-line"><span class="token coord">@@ -3,38 +3,41 @@</span> </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"># Contributor: Hilton Medeiros &lt;[email protected]&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"># Contributor: Dave Reisner &lt;[email protected]&gt; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line">pkgname=libgit2 </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line">pkgname=libgit2-static </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">srcname=libgit2 </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">pkgver=1.1.0 </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">pkgrel=1 </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">epoch=1 </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line">pkgdesc=&#x27;A linkable library for Git&#x27; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line">pkgdesc=&#x27;libgit2 static library for cross compile purpose&#x27; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">arch=(&#x27;x86_64&#x27;) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">url=&quot;https://libgit2.github.com/&quot; </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line">depends=(&#x27;glibc&#x27; &#x27;http-parser&#x27; &#x27;openssl&#x27; &#x27;pcre&#x27; &#x27;zlib&#x27;) </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token prefix deleted">-</span><span class="token line">makedepends=(&#x27;cmake&#x27; &#x27;libssh2&#x27; &#x27;python&#x27;) </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token prefix deleted">-</span><span class="token line">provides=(&#x27;libgit2.so&#x27;) </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line">depends=(&#x27;glibc&#x27; &#x27;http-parser&#x27; &#x27;pcre&#x27; &#x27;zlib&#x27; &#x27;libgit2&#x27;) </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">makedepends=(&#x27;cmake&#x27; &#x27;python&#x27;) </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">provides=(&#x27;libgit2.a&#x27;) </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">license=(&#x27;GPL2&#x27;) </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line">source=(&quot;$pkgname-$pkgver.tar.gz::https://github.com/libgit2/libgit2/archive/v${pkgver}.tar.gz&quot; </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token prefix deleted">-</span><span class="token line"> &quot;${pkgname}-0.99.0-remove_http-parse_incompatible_tests.patch&quot;) </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line">source=(&quot;$srcname-$pkgver.tar.gz::https://github.com/libgit2/libgit2/archive/v${pkgver}.tar.gz&quot; </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line"> &quot;${srcname}-0.99.0-remove_http-parse_incompatible_tests.patch&quot;) </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">sha512sums=(&#x27;347bb68900181b44fa58a0417506c91383adb965607fce049a5b4c57ac9cc286e0a140d164c339b50fb6cd6951f47757c2917a2df44ba004bfaa4fb643946bb8&#x27; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &#x27;e73072424c9c1870eaaf93b3451295ef7333b59f6cb8a6897dd690b69a20aaeb70f00d15a692c1d9e0745d5ef16bbbb912fbd570d8bc83ca0b7d57f32025bf94&#x27;) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">b2sums=(&#x27;2a1c1f71d2a2e06448c78eb46028fdcfd59682dccf2365851c4bd059cdd78842320f9a5ba7345e761611a5b4eba634faf2e26cc669097da0ba2e1c832c23059f&#x27; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> &#x27;cdca2012f772afea99436faa02f80697dc9042a6eb5ae14f8ee8ba9e100a65b936cdfaf84ec0361543c70859375c823a25cfee52b0face40b8dea2ec2cf1de59&#x27;) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">prepare() { </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> cd &quot;$pkgname-$pkgver&quot; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> cd &quot;$srcname-$pkgver&quot; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> # removing tests that are only compatible with the (modified) vendored </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> # version of http-parser, but not with upstream http-parser </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> patch -Np1 -i &quot;../${pkgname}-0.99.0-remove_http-parse_incompatible_tests.patch&quot; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> patch -Np1 -i &quot;../${srcname}-0.99.0-remove_http-parse_incompatible_tests.patch&quot; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">build() { </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> cd &quot;$pkgname-$pkgver&quot; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> cd &quot;$srcname-$pkgver&quot; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> cmake -DCMAKE_INSTALL_PREFIX=/usr \ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> -DCMAKE_BUILD_TYPE=&#x27;None&#x27; \ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> -DUSE_HTTP_PARSER=system \ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> -DTHREADSAFE=ON \ </span></span></span><span class="code-line inserted"><span class="token unchanged"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> -DBUILD_SHARED_LIBS=OFF \ </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line"> -DUSE_SSH=OFF \ </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> -Wno-dev \ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> -B build \ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> -S . </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span>@@ -42,14 +45,11 @@ build() { </span><span class="code-line"><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">check() { </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> cd &quot;$pkgname-$pkgver&quot; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> cd &quot;$srcname-$pkgver&quot; </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line"> make -C build test VERBOSE=1 </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token unchanged prefix"> </span><span class="token line">package() { </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line"> depends+=(&#x27;libssh2.so&#x27;) </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token prefix deleted">-</span><span class="token line"> cd &quot;$pkgname-$pkgver&quot; </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token prefix deleted">-</span><span class="token line"> make -C build DESTDIR=&quot;$pkgdir&quot; install </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token prefix deleted">-</span><span class="token line"> install -vDm 644 {AUTHORS,README.md} \ </span></span></span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token line"></span><span class="token prefix deleted">-</span><span class="token line"> -t &quot;${pkgdir}/usr/share/doc/${pkgname}&quot; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token prefix inserted">+</span><span class="token line"> cd &quot;$srcname-$pkgver&quot; </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token prefix inserted">+</span><span class="token line"> install -vD -m755 ./build/libgit2.a $pkgdir/usr/lib/libgit2.a </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token unchanged prefix"> </span><span class="token line">} </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span></code></pre></div><p>完整文件:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># Maintainer: Lukas Fleischer &lt;[email protected]&gt;</span> </span><span class="code-line"><span class="token comment"># Contributor: David Runge &lt;[email protected]&gt;</span> </span><span class="code-line"><span class="token comment"># Contributor: Hilton Medeiros &lt;[email protected]&gt;</span> </span><span class="code-line"><span class="token comment"># Contributor: Dave Reisner &lt;[email protected]&gt;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token variable assign-left">pkgname</span><span class="token operator">=</span>libgit2-static </span><span class="code-line"><span class="token variable assign-left">srcname</span><span class="token operator">=</span>libgit2 </span><span class="code-line"><span class="token variable assign-left">pkgver</span><span class="token operator">=</span><span class="token number">1.1</span>.0 </span><span class="code-line"><span class="token variable assign-left">pkgrel</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">epoch</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token variable assign-left">pkgdesc</span><span class="token operator">=</span><span class="token string">&#x27;libgit2 static library for cross compile purpose&#x27;</span> </span><span class="code-line"><span class="token variable assign-left">arch</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;x86_64&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">url</span><span class="token operator">=</span><span class="token string">&quot;https://libgit2.github.com/&quot;</span> </span><span class="code-line"><span class="token variable assign-left">depends</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;glibc&#x27;</span> <span class="token string">&#x27;http-parser&#x27;</span> <span class="token string">&#x27;pcre&#x27;</span> <span class="token string">&#x27;zlib&#x27;</span> <span class="token string">&#x27;libgit2&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">makedepends</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;cmake&#x27;</span> <span class="token string">&#x27;python&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">provides</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;libgit2.a&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">license</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;GPL2&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">source</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&quot;<span class="token variable">$srcname</span>-<span class="token variable">$pkgver</span>.tar.gz::https://github.com/libgit2/libgit2/archive/v<span class="token variable">${pkgver}</span>.tar.gz&quot;</span> </span><span class="code-line"> <span class="token string">&quot;<span class="token variable">${srcname}</span>-0.99.0-remove_http-parse_incompatible_tests.patch&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">sha512sums</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;347bb68900181b44fa58a0417506c91383adb965607fce049a5b4c57ac9cc286e0a140d164c339b50fb6cd6951f47757c2917a2df44ba004bfaa4fb643946bb8&#x27;</span> </span><span class="code-line"> <span class="token string">&#x27;e73072424c9c1870eaaf93b3451295ef7333b59f6cb8a6897dd690b69a20aaeb70f00d15a692c1d9e0745d5ef16bbbb912fbd570d8bc83ca0b7d57f32025bf94&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">b2sums</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">&#x27;2a1c1f71d2a2e06448c78eb46028fdcfd59682dccf2365851c4bd059cdd78842320f9a5ba7345e761611a5b4eba634faf2e26cc669097da0ba2e1c832c23059f&#x27;</span> </span><span class="code-line"> <span class="token string">&#x27;cdca2012f772afea99436faa02f80697dc9042a6eb5ae14f8ee8ba9e100a65b936cdfaf84ec0361543c70859375c823a25cfee52b0face40b8dea2ec2cf1de59&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">prepare</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">$srcname</span>-<span class="token variable">$pkgver</span>&quot;</span> </span><span class="code-line"> <span class="token comment"># removing tests that are only compatible with the (modified) vendored</span> </span><span class="code-line"> <span class="token comment"># version of http-parser, but not with upstream http-parser</span> </span><span class="code-line"> patch <span class="token variable parameter">-Np1</span> <span class="token variable parameter">-i</span> <span class="token string">&quot;../<span class="token variable">${srcname}</span>-0.99.0-remove_http-parse_incompatible_tests.patch&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">$srcname</span>-<span class="token variable">$pkgver</span>&quot;</span> </span><span class="code-line"> cmake <span class="token variable parameter">-DCMAKE_INSTALL_PREFIX</span><span class="token operator">=</span>/usr <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-DCMAKE_BUILD_TYPE</span><span class="token operator">=</span><span class="token string">&#x27;None&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-DUSE_HTTP_PARSER</span><span class="token operator">=</span>system <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-DTHREADSAFE</span><span class="token operator">=</span>ON <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-DBUILD_SHARED_LIBS</span><span class="token operator">=</span>OFF <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-DUSE_SSH</span><span class="token operator">=</span>OFF <span class="token punctuation">\</span> </span><span class="code-line"> -Wno-dev <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-B</span> build <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-S</span> <span class="token builtin class-name">.</span> </span><span class="code-line"> <span class="token function">make</span> <span class="token variable parameter">-C</span> build <span class="token variable assign-left">VERBOSE</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">check</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">$srcname</span>-<span class="token variable">$pkgver</span>&quot;</span> </span><span class="code-line"> <span class="token function">make</span> <span class="token variable parameter">-C</span> build <span class="token builtin class-name">test</span> <span class="token variable assign-left">VERBOSE</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">package</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">cd</span> <span class="token string">&quot;<span class="token variable">$srcname</span>-<span class="token variable">$pkgver</span>&quot;</span> </span><span class="code-line"> <span class="token function">install</span> <span class="token variable parameter">-vD</span> <span class="token variable parameter">-m755</span> ./build/libgit2.a <span class="token variable">$pkgdir</span>/usr/lib/libgit2.a </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://github.com/libgit2/libgit2">https://github.com/libgit2/libgit2</a></p><p><a href="https://pkgs.alpinelinux.org/package/edge/community/x86_64/libgit2-static">https://pkgs.alpinelinux.org/package/edge/community/x86_64/libgit2-static</a></p><p><a href="https://packages.ubuntu.com/focal/amd64/libgit2-dev/filelist">https://packages.ubuntu.com/focal/amd64/libgit2-dev/filelist</a></p><p><a href="https://wiki.archlinux.org/index.php/Arch_Build_System#Retrieve_PKGBUILD_source_using_Git">https://wiki.archlinux.org/index.php/Arch_Build_System#Retrieve_PKGBUILD_source_using_Git</a></p><p><a href="https://archlinux.org/packages/extra/x86_64/libgit2/">https://archlinux.org/packages/extra/x86_64/libgit2/</a></p> Mon, 05 Apr 2021 16:08:02 GMT ttyS3 archlinuxstatic-libpackageaurabs https://ttys3.dev/blog/neovim-vala-lsp-integration-tips Neovim Vala Lsp Integration Tips https://ttys3.dev/blog/neovim-vala-lsp-integration-tips <h2 id="the-issue"><a href="#the-issue" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>The Issue</h2><p>如果不是用到了一个叫 <a href="https://github.com/phw/peek">peek</a> 的录屏软件,我可能没听过这个叫 vala 的语言,GNOME 搞出来的东西。</p><p>老灯日常用的 <a href="https://gitlab.gnome.org/GNOME/geary">geary</a> 邮件客户端和 <a href="https://github.com/phw/peek">peek</a> 都是这个语言编写的。</p><p>老灯发现neovim 官方的 vala lang server 配置无法适用于 peek 这个项目。已经提交了 PR ( <a href="https://github.com/neovim/nvim-lspconfig/pull/789">https://github.com/neovim/nvim-lspconfig/pull/789</a> ), 不过这个合并效率真是低,都两周了,还没动静,没给close 也没给merge.</p><p>neovim 官方的 vala lang server 配置甚至无法用于正常浏览 <a href="https://github.com/benwaffle/vala-language-server">vala-language-server</a> 的源码。</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">git</span> clone https://github.com/benwaffle/vala-language-server </span><span class="code-line"><span class="token builtin class-name">cd</span> vala-language-server </span><span class="code-line">nvim </span></code></pre></div><p>然后我们在 neovim 中打开 <code>src/server.vala</code>,然后 neovim lsp 会在<code>src</code>目录下找到一个“假”的<code>meson.build</code>文件 (真正的 meson.build 文件在项目根目录下),根据 vala lang server 的逻辑,它会在这个“project root&quot;(假的) 下面执行 <code>meson build</code>, 很明显这个命令会失败,因为这个不是真正的 meson.build 文件,而只是一个被根目录下的 meson.build 文件 包含进来的 include 文件 (姑且这么说吧,你 get 到意思就行)。然后 vala lang server 就报错了(实际上它输出的是 meson 的 stderr 错误信息):</p><blockquote><p>ERROR: First statement must be a call to project</p></blockquote><h2 id="the-solution"><a href="#the-solution" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>The Solution</h2><p>根据 meson 的报错信息,我们知道,meson.build 文件的第一行有效指令一定是 <strong>a call to project</strong>.</p><p>这里老灯用的有效指令,其实主要是指排除comment. <strong>a call to project</strong> 即调用 <code>project()</code></p><p>在官方没合并老灯的 PR 前,只能手动在配置那里hack了:</p><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line"><span class="token comment">-- https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#vala_ls</span> </span><span class="code-line"><span class="token keyword">local</span> meson_matcher <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>path<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">local</span> pattern <span class="token operator">=</span> <span class="token string">&quot;meson.build&quot;</span> </span><span class="code-line"> <span class="token keyword">local</span> f <span class="token operator">=</span> vim<span class="token punctuation">.</span>fn<span class="token punctuation">.</span><span class="token function">glob</span><span class="token punctuation">(</span>util<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span> pattern<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> f <span class="token operator">==</span> <span class="token string">&#x27;&#x27;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token keyword">nil</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">for</span> line <span class="token keyword">in</span> io<span class="token punctuation">.</span><span class="token function">lines</span><span class="token punctuation">(</span>f<span class="token punctuation">)</span> <span class="token keyword">do</span> </span><span class="code-line"> <span class="token comment">-- skip meson comments</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">not</span> line<span class="token punctuation">:</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token string">&#x27;^%s*#.*&#x27;</span><span class="token punctuation">)</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token keyword">local</span> str <span class="token operator">=</span> line<span class="token punctuation">:</span><span class="token function">gsub</span><span class="token punctuation">(</span><span class="token string">&#x27;%s+&#x27;</span><span class="token punctuation">,</span> <span class="token string">&#x27;&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> str <span class="token operator">~=</span> <span class="token string">&#x27;&#x27;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token keyword">if</span> str<span class="token punctuation">:</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token string">&#x27;^project%(&#x27;</span><span class="token punctuation">)</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token keyword">return</span> path </span><span class="code-line"> <span class="token keyword">else</span> </span><span class="code-line"> <span class="token keyword">break</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"><span class="token keyword">end</span> </span><span class="code-line"> </span><span class="code-line">lsp<span class="token punctuation">.</span>vala_ls<span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">{</span> </span><span class="code-line"> on_attach <span class="token operator">=</span> mix_attach<span class="token punctuation">,</span> </span><span class="code-line"> capabilities <span class="token operator">=</span> lsp_status<span class="token punctuation">.</span>capabilities<span class="token punctuation">,</span> </span><span class="code-line"> cmd <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">&#x27;vala-language-server&#x27;</span><span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> root_dir <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>fname<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">local</span> root <span class="token operator">=</span> util<span class="token punctuation">.</span><span class="token function">search_ancestors</span><span class="token punctuation">(</span>fname<span class="token punctuation">,</span> meson_matcher<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">return</span> root <span class="token keyword">or</span> util<span class="token punctuation">.</span><span class="token function">find_git_ancestor</span><span class="token punctuation">(</span>fname<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">end</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span> </span></code></pre></div><p>ps: 关于上面配置里的 mix_attach 和 lsp_status 请参考老灯之前写的《<a href="/post/nvim/neovim-c-cpp-lsp-integration-tips/">Neovim C Cpp Lsp Integration Tips</a>》</p><p>这里主要是告诉 neovim lsp, 要怎么确定这个 project root, 所谓的 project root, neovim lsp config 的逻辑是,</p><p>先找到项目的 meson.build 文件, 该文件所在目录,即project root,否则,就尝试找 git 仓库.</p><p>这里我们简单地给查找 meson.build 文件的方法 hack 了一下,跳过评论并且去除行两端的空格后,我们简单地判断此行是否以<code>project(</code>开头,即可过滤掉那些假的 meson.build 文件</p><p>其实 neovim lsp config 这个判断方法也只是针对大部分情况。但是老灯觉得,对于大部分情况已经 OK 了,毕竟,作为一个公共配置,它无法兼顾所有情况。</p><p>根据 <a href="https://wiki.gnome.org/Projects/Vala/Tools">GNOME 官方说明</a>:meson 是 Vala 主要的构建系统。</p><blockquote><p>Meson - a front end to the Ninja build system with Vala support (<strong>The main build system for Vala</strong>)</p></blockquote><p>因此,只判断meson.build 文件,对于大部分 Vala 项目来说应该是 OK 的</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://github.com/benwaffle/vala-language-server">https://github.com/benwaffle/vala-language-server</a></p><p><a href="https://wiki.gnome.org/Projects/Vala/Tools">https://wiki.gnome.org/Projects/Vala/Tools</a></p><p><a href="https://mesonbuild.com/Syntax.html#comments">https://mesonbuild.com/Syntax.html#comments</a></p><p><a href="https://github.com/phw/peek">https://github.com/phw/peek</a></p><p><a href="https://gitlab.gnome.org/GNOME/geary">https://gitlab.gnome.org/GNOME/geary</a></p><p><a href="https://github.com/benwaffle/vala-language-server">https://github.com/benwaffle/vala-language-server</a></p> Mon, 05 Apr 2021 15:03:31 GMT ttyS3 neovimlsplang-servertipsvalagnome https://ttys3.dev/blog/neovim-c-cpp-lsp-integration-tips Neovim C Cpp Lsp Integration Tips https://ttys3.dev/blog/neovim-c-cpp-lsp-integration-tips <p>本文主要按 neovim lsp 来讲的,但是其中关于 lang server 的很多东西,其实是通用的。简单在此记录,备忘。</p><h2 id="common-lsp-config"><a href="#common-lsp-config" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>common lsp config</h2><p>一般除了跳转定义,老灯还启用了 <code>completion</code> 自动完成以及 <code>lsp-status</code> 用于状态显示。</p><p>这里定义了一个公用的 <code>mix_attach</code> 用于lsp <code>on_attach</code> 事件</p><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line"><span class="token keyword">local</span> lsp_status <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&#x27;lsp-status&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line">lsp_status<span class="token punctuation">.</span><span class="token function">register_progress</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line">lsp_status<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span> </span><span class="code-line"> indicator_errors <span class="token operator">=</span> <span class="token string">&quot;❌&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> indicator_warnings <span class="token operator">=</span> <span class="token string">&quot;⚠️ &quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> indicator_info <span class="token operator">=</span> <span class="token string">&quot;ℹ️ &quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token comment">-- https://emojipedia.org/tips/</span> </span><span class="code-line"> indicator_hint <span class="token operator">=</span> <span class="token string">&quot;💡&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> indicator_ok <span class="token operator">=</span> <span class="token string">&quot;✅&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">local</span> cmp <span class="token operator">=</span> require<span class="token string">&#x27;completion&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">--@param client: (required, vim.lsp.client)</span> </span><span class="code-line"><span class="token keyword">local</span> mix_attach <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span> </span><span class="code-line"> lsp_status<span class="token punctuation">.</span><span class="token function">on_attach</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span> </span><span class="code-line"> cmp<span class="token punctuation">.</span><span class="token function">on_attach</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span> </span><span class="code-line"><span class="token keyword">end</span> </span></code></pre></div><h2 id="neovim-clangd-lsp-setup"><a href="#neovim-clangd-lsp-setup" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>neovim clangd lsp setup</h2><p>clangd 的配置,主要参考 <a href="https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#clangd">nvim-lspconfig 文档</a></p><p>注意这里对 handlers 的配置参考了 <a href="https://github.com/nvim-lua/lsp-status.nvim#example-use">lsp-status 的示例文档</a>,</p><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line"><span class="token comment">-- https://clangd.llvm.org/features.html</span> </span><span class="code-line">lsp<span class="token punctuation">.</span>clangd<span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">{</span> </span><span class="code-line"> handlers <span class="token operator">=</span> lsp_status<span class="token punctuation">.</span>extensions<span class="token punctuation">.</span>clangd<span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> init_options <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> clangdFileStatus <span class="token operator">=</span> <span class="token keyword">true</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> on_attach <span class="token operator">=</span> mix_attach<span class="token punctuation">,</span> </span><span class="code-line"> capabilities <span class="token operator">=</span> lsp_status<span class="token punctuation">.</span>capabilities </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span> </span></code></pre></div><h2 id="项目配置----支持clangd"><a href="#项目配置----支持clangd" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>项目配置 -- 支持clangd</h2><p>lsp 配置实际上比较简单,实际使用中,遇到问题的主要是关于如何让 lang server ( clangd 或 ccls ) 找到那些头文件。</p><blockquote><p>To understand your source code, clangd needs to know your <strong>build flags</strong>. (This is just a fact of life in C++, <strong>source files are not self-contained</strong>).</p><p>By default, clangd will assume your code is built as <code>clang some_file.cc</code>, and you’ll probably get spurious errors about missing <code>#include</code>d files, etc. There are a couple of ways to fix this.</p></blockquote><p>主要原因在于,C 和 C++ 这俩语言比较古老,不像 Rust 或 Golang 那样自带包管理, 因此需要外部工具来帮助 lang server 理解代码。对于 clangd 来说,主要有两种解决办法:</p><h3 id="1-compile_commandsjson-法"><a href="#1-compile_commandsjson-法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. compile_commands.json 法</h3><blockquote><p>This file provides compile commands for every source file in a project. It is usually generated by tools. Clangd will look in <strong>the parent directories of the files</strong> you edit looking for it.</p></blockquote><p>虽然 clangd 的文档里说 clangd 会在你所编辑的文件的父目录中查找 compile_commands.json, 但实际使用中老灯发现能自动加载 build/compile_commands.json 文件,不知道是 neovim hack了还是 clangd 本身支持?</p><p>没时间细纠了,先这样吧。如果谁知道答案麻烦告知一下。</p><h4 id="11-基于-cmake-的项目"><a href="#11-基于-cmake-的项目" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1.1 基于 CMake 的项目</h4><p>这里又分两种情况,对于基于 CMake 的项目,只需要启用 <a href="https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html"><code>CMAKE_EXPORT_COMPILE_COMMANDS</code></a> 即可自动生成 <code>compile_commands.json</code> 文件。</p><p>启用 <code>CMAKE_EXPORT_COMPILE_COMMANDS</code>的方法主要有两种:</p><p>一是直接在命令行参数中指定,比如:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">cmake <span class="token variable parameter">-B</span> build <span class="token variable parameter">-DCMAKE_EXPORT_COMPILE_COMMANDS</span><span class="token operator">=</span><span class="token number">1</span> <span class="token builtin class-name">.</span> </span><span class="code-line"><span class="token comment"># or</span> </span><span class="code-line"><span class="token comment"># cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=1</span> </span></code></pre></div><p>二是在 CMakeLists.txt 中添加:</p><div class="relative"><pre><code class="code-highlight language-cmake"><span class="code-line"><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token variable">CMAKE_EXPORT_COMPILE_COMMANDS</span> <span class="token boolean">ON</span><span class="token punctuation">)</span> </span></code></pre></div><h4 id="12-基于其它构建系统的项目"><a href="#12-基于其它构建系统的项目" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1.2 基于其它构建系统的项目</h4><p>对于其它构建系统 ( 主要是一些上古的 Makefile 类项目),要生成 compile_commands.json 需要用到一个叫 <a href="https://github.com/rizsotto/Bear">Bear</a> 的工具。</p><blockquote><p>Bear is a tool that generates a compilation database for clang tooling.</p><p>The <a href="http://clang.llvm.org/docs/JSONCompilationDatabase.html">JSON compilation database</a> is used in the clang project to provide information on how a single compilation unit is processed. With this, it is easy to re-run the compilation with alternate programs.</p><p>One way to get a compilation database is to use <code>cmake</code> as the build tool. Passing <code>-DCMAKE_EXPORT_COMPILE_COMMANDS=ON</code> to cmake generates the <code>compile_commands.json</code> file into the current directory.</p><p>For non-cmake projects, Bear generates the JSON file during the build process.</p></blockquote><p>Bear 的用法比较简单,直接在构建命令前面加bear 即可,如: <code>bear make -j14</code></p><p>Bear 安装:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token comment"># fedora</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> bear </span><span class="code-line"><span class="token comment"># ubuntu</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> <span class="token variable parameter">-y</span> bear </span><span class="code-line"><span class="token comment"># archlinux cn</span> </span><span class="code-line"><span class="token function">sudo</span> pacman <span class="token variable parameter">-S</span> bear </span><span class="code-line"><span class="token comment"># archlinux aur</span> </span><span class="code-line">paru <span class="token variable parameter">-S</span> bear </span></code></pre></div><p>除了 Bear, 还有其它工具也能生成 <code>compile_commands.json</code>:</p><p><a href="http://ninja-build.org/">ninja build</a> 也支持生成,如:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token comment"># Format: ninja -t compdb rule_names... &gt; compile_commands.json</span> </span><span class="code-line">ninja <span class="token variable parameter">-C</span> out/Release <span class="token variable parameter">-t</span> compdb cxx cc <span class="token operator">&gt;</span> compile_commands.json </span></code></pre></div><p><a href="https://mesonbuild.com/">meson</a>会自动生成:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">meson build <span class="token comment"># generates compile_commands.json in the `build` directory</span> </span></code></pre></div><p><a href="https://github.com/nickdiego/compiledb">https://github.com/nickdiego/compiledb</a> (基于python)</p><p><a href="https://github.com/rizsotto/scan-build">https://github.com/rizsotto/scan-build</a> (python版,基于libear, uses Bear as a backend)</p><h3 id="2-compile_flagstxt-法"><a href="#2-compile_flagstxt-法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. compile_flags.txt 法</h3><blockquote><p>If all files in a project <strong>use the same build flags</strong>, you can put those flags one-per-line in <code>compile_flags.txt</code> in your source root.</p><p>Clangd will assume the compile command is <code>clang $FLAGS some_file.cc</code>.</p><p>Creating this file by hand is a reasonable place to start if your project is quite simple.</p></blockquote><p>compile_flags.txt 法主要是针对于项目中的所有文件都使用相同的 build flags 的情况。这个时候,你可以手撸一个 compile_flags.txt 来帮助 clangd 理解你的代码。</p><blockquote><p>For <strong>simple projects</strong>, Clang tools also recognize a <code>compile_flags.txt</code> file. This should contain <strong>one argument per line</strong>. The same flags will be used to compile any file.</p></blockquote><p>需要注意的是,This should contain <strong>one argument per line</strong>.</p><p>例如:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token operator">-</span>xc<span class="token operator">++</span> </span><span class="code-line"><span class="token operator">-</span><span class="token constant">I</span> </span><span class="code-line">libwidget<span class="token operator">/</span>include<span class="token operator">/</span> </span></code></pre></div><p>这里 -I libwidget/include 是两个参数,因此要各放一行 ( <strong>one argument per line</strong> )。</p><p>如果是相对路径,则该路径<strong>相对于 compile_flags.txt 文件所在目录</strong>。</p><h2 id="neovim-ccls-lsp-setup"><a href="#neovim-ccls-lsp-setup" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>neovim ccls lsp setup</h2><p>一般情况下使用clangd 即可了,没有必要配置两个lang server.</p><p>如果由于某些原因需要使用 ccls 的,老灯这里也说一下。</p><p><a href="https://mesonbuild.com/%E9%85%8D%E7%BD%AE%E9%83%A8%E5%88%86%E6%AF%94%E8%BE%83%E7%AE%80%E5%8D%95%EF%BC%8C%E4%B8%BB%E8%A6%81%E6%98%AF%E5%8F%82%E8%80%83">https://mesonbuild.com/配置部分比较简单,主要是参考</a> <a href="https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#ccls">nvim-lspconfig 关于 ccls 的文档</a></p><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line"><span class="token comment">-- https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#ccls</span> </span><span class="code-line"><span class="token comment">-- https://github.com/MaskRay/ccls/wiki</span> </span><span class="code-line">lsp<span class="token punctuation">.</span>ccls<span class="token punctuation">.</span><span class="token function">setup</span> <span class="token punctuation">{</span> </span><span class="code-line"> init_options <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> compilationDatabaseDirectory <span class="token operator">=</span> <span class="token string">&quot;build&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> index <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> threads <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> clang <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> excludeArgs <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">&quot;-frounding-math&quot;</span><span class="token punctuation">}</span> <span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h2 id="项目配置----支持ccls"><a href="#项目配置----支持ccls" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>项目配置 -- 支持ccls</h2><p>根据ccls wiki:</p><blockquote><p>ccls typically indexes an entire project. In order for this to work properly, <code>ccls</code> needs to be able to obtain the source file list and their compilation command lines.</p><p>There are two main ways this happens:</p><ol><li>Provide <code>compile_commands.json</code> at <strong>the project root</strong></li><li>Provide a <a href="https://github.com/MaskRay/ccls/wiki/Project-Setup#ccls-file"><code>.ccls</code> file</a>. It is a line-based text file describing compiler flags. Recursively listed source files (headers excluded) will be indexed. Use an empty <code>.ccls</code> to get started (if you don&#x27;t need specific -I, -D, etc).</li></ol><p>If neither exists, then when ccls starts it will not index anything: instead it will wait for LSP clients to open files and index only those files.</p></blockquote><p>注意 ccls 只会在 project root 搜索 <code>compile_commands.json</code>文件。</p><blockquote><p>If your <code>compile_commands.json</code> is not kept in the project root, set the initialization option <code>compilationDatabaseDirectory</code> to an alternative directory containing <code>compile_commands.json</code>.</p></blockquote><p>因此前面我们的 neovim lsp 配置的时候,指定了 <code>init_options.compilationDatabaseDirectory = &quot;build&quot;</code></p><p>第一种方法直接参考前面 clangd 部分。</p><p>第二种方法,参考ccls wiki: <a href="https://github.com/MaskRay/ccls/wiki/Project-Setup"></a><a href="https://github.com/MaskRay/ccls/wiki/Project-Setup#ccls-file">https://github.com/MaskRay/ccls/wiki/Project-Setup#ccls-file</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#ccls">https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#ccls</a></p><p><a href="https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#clangd">https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#clangd</a></p><p><a href="https://github.com/nvim-lua/lsp-status.nvim#example-use">https://github.com/nvim-lua/lsp-status.nvim#example-use</a></p><p><a href="https://clangd.llvm.org/installation.html#project-setup">https://clangd.llvm.org/installation.html#project-setup</a></p><p><a href="https://clangd.llvm.org/extensions.html#switch-between-sourceheader">https://clangd.llvm.org/extensions.html#switch-between-sourceheader</a></p><p><a href="https://github.com/MaskRay/ccls/wiki/Project-Setup">https://github.com/MaskRay/ccls/wiki/Project-Setup</a></p><p><a href="https://github.com/MaskRay/ccls/wiki">https://github.com/MaskRay/ccls/wiki</a></p><p><a href="https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html">https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html</a></p><p><a href="https://clang.llvm.org/docs/JSONCompilationDatabase.html">https://clang.llvm.org/docs/JSONCompilationDatabase.html</a></p><p><a href="https://github.com/rizsotto/Bear">https://github.com/rizsotto/Bear</a></p><p><a href="http://ninja-build.org/">http://ninja-build.org/</a></p><p><a href="https://mesonbuild.com/">https://mesonbuild.com/</a></p> Mon, 05 Apr 2021 13:40:34 GMT ttyS3 clangdlsplang-serverneovimtips https://ttys3.dev/blog/rust-cross-compile-darwin-target-troubleshooting Rust 交叉编译 OSX 二进制失败原因分析 https://ttys3.dev/blog/rust-cross-compile-darwin-target-troubleshooting <h2 id="缘由"><a href="#缘由" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h2><p>起因还是在ArchLinux下交叉编译 <a href="https://github.com/ttys3/git-cz"></a><a href="https://github.com/ttys3/git-cz">git-cz</a> OSX 二进制失败。</p><p>这个问题老灯折腾了很久,搞得几乎都要放弃了。</p><p>因为在 Linux 下交叉编译 darwin 平台的教程并不太多,能找到的资料也不尽是相同或相似的问题。</p><p>但老灯之前在 Fedora 33 及 Ubuntu 21.04 beta 下都能成功编译,因此,这个周末正好有时间 ,还是坚持分析了一下原因。</p><h2 id="问题描述"><a href="#问题描述" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>问题描述</h2><p>git-cz 依赖 libgit2 的 rust 绑定库 ( <a href="https://github.com/rust-lang/git2-rs">https://github.com/rust-lang/git2-rs</a> ),C 绑定部分代码是里面的子包 libgit2-sys ( <a href="https://crates.io/crates/libgit2-sys">https://crates.io/crates/libgit2-sys</a> ) , 因此最后链接阶段,在交叉编译时,肯定是要链接 libgit2 的静态库的(交叉编译时一般都是静态链接,如果动态链接会很麻烦。 比如golang也是,且 golang 在交叉编译时甚至是直接默认关闭 cgo 的)</p><p>在编译完成最后 的link阶段报错:</p><blockquote><p>Compiling git2 v0.13.17 error: linking with <code>/usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin20.4-clang</code> failed: exit code: 1</p></blockquote><p>cargo 加上 <code>--verbose</code> 参数后,得到如下信息:</p><blockquote><p>= note: ld: library not found for -lgit2 clang-11: error: linker command failed with exit code 1 (use -v to see invocation)</p></blockquote><p>以老灯的经验判断,应该是链接的时候没有找到 libgit2 的静态库。</p><p>但是这个库应该跟 ArchLinux 系统的静态库没有关系。因为 Linux 的二进制文件是 ELF 格式的,而不是苹果的Mach-O 64-bit x86_64.</p><h2 id="pkg-config-rs-和-cc-rs"><a href="#pkg-config-rs-和-cc-rs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>pkg-config-rs 和 cc-rs</h2><p>于是老灯去查看了一下 <a href="https://crates.io/crates/libgit2-sys">libgit2-sys</a> 的源码,发现其实它是会自动编译 libgit2 的,并且它的Build-Dependencies 依赖有 <a href="https://crates.io/crates/pkg-config">https://crates.io/crates/pkg-config</a> 和 <a href="https://crates.io/crates/cc">https://crates.io/crates/cc</a></p><p>关于 pkg-config-rs 和 cc-rs 支持的环境变量配置,这里老灯直接把官方文档里的摘抄过来,老灯觉得这里的描述几乎全部是重要的。</p><p>我们看下pkg-config-rs的介绍:</p><blockquote><p>A simple library meant to be used as a build dependency with Cargo packages in order to use the system <code>pkg-config</code> tool (if available) to determine where a library is located.</p></blockquote><p><strong>External configuration via target-scoped environment variables</strong></p><p>In cross-compilation context, it is useful to manage separately <code>PKG_CONFIG_PATH</code> and a few other variables for the <code>host</code> and the <code>target</code> platform.</p><p>The supported variables are: <code>PKG_CONFIG_PATH</code>, <code>PKG_CONFIG_LIBDIR</code>, and <code>PKG_CONFIG_SYSROOT_DIR</code>.</p><p>Each of these variables can also be supplied with certain prefixes and suffixes, in the following prioritized order:</p><ol><li><code>&lt;var&gt;_&lt;target&gt;</code> - for example, <code>PKG_CONFIG_PATH_x86_64-unknown-linux-gnu</code></li><li><code>&lt;var&gt;_&lt;target_with_underscores&gt;</code> - for example, <code>PKG_CONFIG_PATH_x86_64_unknown_linux_gnu</code></li><li><code>&lt;build-kind&gt;_&lt;var&gt;</code> - for example, <code>HOST_PKG_CONFIG_PATH</code> or <code>TARGET_PKG_CONFIG_PATH</code></li><li><code>&lt;var&gt;</code> - a plain <code>PKG_CONFIG_PATH</code></li></ol><blockquote><p>This crate will allow <code>pkg-config</code> to be used in cross-compilation if <code>PKG_CONFIG_SYSROOT_DIR</code> or <code>PKG_CONFIG</code> is set. You can set <code>PKG_CONFIG_ALLOW_CROSS=1</code> to bypass the compatibility check, but please note that enabling use of <code>pkg-config</code> in cross-compilation without appropriate sysroot and search paths set is likely to break builds.</p><p>Some Rust sys crates support building vendored libraries from source, which may be a work around for lack of cross-compilation support in <code>pkg-config</code>.</p></blockquote><p>这里最关键的是后面那段话。</p><p>如果设置了<code>PKG_CONFIG_SYSROOT_DIR</code>或<code>PKG_CONFIG</code>,则此crate将允许<code>pkg-config</code>用于交叉编译。 您可以设置<code>PKG_CONFIG_ALLOW_CROSS=1 </code>以绕过兼容性检查,但是请注意,<strong>在没有适当的sysroot和搜索路径设置的情况下, 在交叉编译中启用pkg-config可能会破坏构建。</strong></p><p>一些Rust sys crates支持从源码构建vendor库,这可能是由于pkg-config缺乏交叉编译支持而采用的变通方案。</p><p><a href="https://crates.io/crates/libgit2-sys">libgit2-sys</a> 就属于那种支持从源码构建vendor库的sys crate, 构建过程中它会自动 clone libgit2 的源码然后编译成静态lib.</p><p>cc-rs 的介绍是:</p><blockquote><p>A build-time dependency for Cargo build scripts to assist in invoking the native C compiler to compile native C code into a static archive to be linked into Rust code.</p></blockquote><p><strong>External configuration via environment variables</strong></p><p>To control the programs and flags used for building, the builder can set a number of different environment variables.</p><ul><li><code>CFLAGS</code> - a series of space separated flags passed to compilers. Note that individual flags cannot currently contain spaces, so doing something like: <code>-L=foo\ bar</code> is not possible.</li><li><code>CC</code> - the actual C compiler used. Note that this is used as an exact executable name, so (for example) no extra flags can be passed inside this variable, and the builder must ensure that there aren&#x27;t any trailing spaces. This compiler must understand the <code>-c</code> flag. For certain <code>TARGET</code>s, it also is assumed to know about other flags (most common is <code>-fPIC</code>).</li><li><code>AR</code> - the <code>ar</code> (archiver) executable to use to build the static library.</li><li><code>CRATE_CC_NO_DEFAULTS</code> - the default compiler flags may cause conflicts in some cross compiling scenarios. Setting this variable will disable the generation of default compiler flags.</li><li><code>CXX...</code> - see <a href="#c-support">C++ Support</a>.</li></ul><p>Each of these variables can also be supplied with certain prefixes and suffixes, in the following prioritized order:</p><ol><li><code>&lt;var&gt;_&lt;target&gt;</code> - for example, <code>CC_x86_64-unknown-linux-gnu</code></li><li><code>&lt;var&gt;_&lt;target_with_underscores&gt;</code> - for example, <code>CC_x86_64_unknown_linux_gnu</code></li><li><code>&lt;build-kind&gt;_&lt;var&gt;</code> - for example, <code>HOST_CC</code> or <code>TARGET_CFLAGS</code></li><li><code>&lt;var&gt;</code> - a plain <code>CC</code>, <code>AR</code> as above.</li></ol><p>If none of these variables exist, cc-rs uses built-in defaults</p><p>In addition to the above optional environment variables, <code>cc-rs</code> has some functions with hard requirements on some variables supplied by <a href="https://doc.rust-lang.org/cargo/reference/build-scripts.html#inputs-to-the-build-script">cargo&#x27;s build-script driver</a> that it has the <code>TARGET</code>, <code>OUT_DIR</code>, <code>OPT_LEVEL</code>, and <code>HOST</code> variables.</p><p>在交叉编译时,为了让编译出来的目标文件是我们需要的,我们一定要设置 <code>CC</code> 和 <code>CXX</code> , 如果在全局设置,比如设置在 .zshrc 文件中的话,那么,直接用 CC 肯定是不行,因为大部分 Makefile 也用到这的环境变量,这会破坏整个系统的构建。关于这一点, cc-rs 早就想到了,允许以 <code>&lt;var&gt;_&lt;target&gt;</code> 或 <code>&lt;var&gt;_&lt;target_with_underscores&gt; </code>的方式按 target 来设置。比如这里我们要的是 x86_64-apple-darwin, 则设置 <code>CC_x86_64-apple-darwin</code> 就OK了,如果觉得下划线+连接符的方式别扭,也可以用 <code>CC_x86_64_apple_darwin</code></p><p>ok, 文档了解得差不多了,我们再回过头来看问题。</p><h2 id="问题解决过程"><a href="#问题解决过程" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>问题解决过程</h2><p>事实上我遇到这个问题的时候,并没有看这些文档,如果早看到上面这些文档,可能问题会得到更快的解决。</p><p>我采用的解决办法是,写一个最小化的 demo, 分别在能成功交叉编译出darwin二进制的机器 和 不能成功编译的机器执行,并记录详细的编译命令到日志,然后用对比工具对比二者在编译过程的命令差异。</p><p>这个方法确实有点笨,但是确实有效发现并解决了问题。</p><p><code>cargo new libgit2-demo</code></p><p>main.rs 内容如下:</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">use</span> <span class="token namespace">git2<span class="token punctuation">::</span></span><span class="token class-name">Repository</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">fn</span> <span class="token function function-definition">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> repo <span class="token operator">=</span> <span class="token keyword">match</span> <span class="token class-name">Repository</span><span class="token punctuation">::</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token string">&quot;/tmp/hello.git&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name">Ok</span><span class="token punctuation">(</span>repo<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> repo<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token class-name">Err</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token property macro">panic!</span><span class="token punctuation">(</span><span class="token string">&quot;failed to init: {}&quot;</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token property macro">println!</span><span class="token punctuation">(</span><span class="token string">&quot;success init repo&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>Cargo.toml 内容如下:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">package</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token property key">name</span> <span class="token punctuation">=</span> <span class="token string">&quot;libgit2-demo&quot;</span> </span><span class="code-line"><span class="token property key">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.1.0&quot;</span> </span><span class="code-line"><span class="token property key">authors</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">&quot;荒野無燈 &lt;*@ttys3.dev&gt;&quot;</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token property key">edition</span> <span class="token punctuation">=</span> <span class="token string">&quot;2018&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">dependencies</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token property key">git2</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token property key">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.13.17&quot;</span><span class="token punctuation">,</span> <span class="token property key">default-features</span> <span class="token punctuation">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property key">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> </span></code></pre></div><p>Makefile 如下:</p><div class="relative"><pre><code class="code-highlight language-makefile"><span class="code-line"><span class="token builtin builtin-target">.PHONY</span><span class="token punctuation">:</span> all clean darwin </span><span class="code-line"> </span><span class="code-line"><span class="token symbol target">all</span><span class="token punctuation">:</span> darwin </span><span class="code-line"> </span><span class="code-line"><span class="token symbol target">darwin</span><span class="token punctuation">:</span> <span class="token keyword">export</span> PKG_CONFIG_ALLOW_CROSS<span class="token operator">=</span>1 </span><span class="code-line"><span class="token symbol target">darwin</span><span class="token punctuation">:</span> <span class="token keyword">export</span> CC<span class="token operator">=</span>o64-clang </span><span class="code-line"><span class="token symbol target">darwin</span><span class="token punctuation">:</span> <span class="token keyword">export</span> CXX<span class="token operator">=</span>o64-clang++ </span><span class="code-line"><span class="token symbol target">darwin</span><span class="token punctuation">:</span> <span class="token keyword">export</span> LIBZ_SYS_STATIC<span class="token operator">=</span>1 </span><span class="code-line"><span class="token symbol target">darwin</span><span class="token punctuation">:</span> </span><span class="code-line"> PATH<span class="token operator">=</span>/usr/local/darwin-ndk-x86_64/bin<span class="token punctuation">:</span><span class="token variable">$$PATH</span> \ </span><span class="code-line"> cargo build --target<span class="token operator">=</span>x86_64-apple-darwin --release --verbose 2&gt;&amp;1 <span class="token operator">|</span> tee arch.log </span><span class="code-line"> </span><span class="code-line"><span class="token symbol target">clean</span><span class="token punctuation">:</span> </span><span class="code-line"> cargo clean </span></code></pre></div><p>测试环境分别是 Ubuntu 21.04 beta 和 ArchLinux, 机器 CPU 分别是 9代 Intel 和 8代 Intel.</p><p>通过对比生成的日志文件 ok.log 和 arch.log, 发现在构建执行 <code>rustc --crate-name libgit2_sys ...</code> 时有个明显的差异。</p><p>ok.log</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"> Running <span class="token variable"><span class="token variable">`</span>rustc --crate-name libgit2_sys <span class="token variable parameter">--edition</span><span class="token operator">=</span><span class="token number">2018</span> /home/ttys3/.cargo/registry/src/mirrors.sjtug.sjtu.edu.cn-4f7dbcce21e258a2/libgit2-sys-0.12.18+1.1.0/lib.rs --error-format<span class="token operator">=</span>json <span class="token variable parameter">--json</span><span class="token operator">=</span>diagnostic-rendered-ansi,artifacts --crate-type lib <span class="token variable parameter">--emit</span><span class="token operator">=</span>dep-info,metadata,link <span class="token variable parameter">-C</span> opt-level<span class="token operator">=</span><span class="token number">3</span> <span class="token variable parameter">-C</span> embed-bitcode<span class="token operator">=</span>no <span class="token variable parameter">-C</span> <span class="token variable assign-left">metadata</span><span class="token operator">=</span>177d6c810f4d7b82 <span class="token variable parameter">-C</span> extra-filename<span class="token operator">=</span>-177d6c810f4d7b82 --out-dir /home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/deps <span class="token variable parameter">--target</span> x86_64-apple-darwin <span class="token variable parameter">-C</span> <span class="token variable assign-left">linker</span><span class="token operator">=</span>/usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin20.4-clang <span class="token variable parameter">-L</span> <span class="token variable assign-left">dependency</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/deps <span class="token variable parameter">-L</span> <span class="token variable assign-left">dependency</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/release/deps <span class="token variable parameter">--extern</span> <span class="token variable assign-left">libc</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/deps/liblibc-d39c361e04f43fde.rmeta <span class="token variable parameter">--extern</span> <span class="token variable assign-left">libz_sys</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/deps/liblibz_sys-87e6342ea6338869.rmeta --cap-lints allow <span class="token variable parameter">-L</span> <span class="token variable assign-left">native</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/build/libgit2-sys-8d26052ab24e9383/out/build <span class="token variable parameter">-l</span> <span class="token variable assign-left">static</span><span class="token operator">=</span>git2 <span class="token variable parameter">-l</span> <span class="token function">iconv</span> <span class="token variable parameter">-l</span> <span class="token variable assign-left">framework</span><span class="token operator">=</span>Security <span class="token variable parameter">-l</span> <span class="token variable assign-left">framework</span><span class="token operator">=</span>CoreFoundation <span class="token variable parameter">-L</span> <span class="token variable assign-left">native</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/build/libz-sys-cffd7e6d65b74042/out/build<span class="token variable">`</span></span> </span></code></pre></div><p>arch.log</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">Running <span class="token variable"><span class="token variable">`</span>rustc --crate-name libgit2_sys <span class="token variable parameter">--edition</span><span class="token operator">=</span><span class="token number">2018</span> /home/ttys3/.cargo/registry/src/mirrors.sjtug.sjtu.edu.cn-4f7dbcce21e258a2/libgit2-sys-0.12.18+1.1.0/lib.rs --error-format<span class="token operator">=</span>json <span class="token variable parameter">--json</span><span class="token operator">=</span>diagnostic-rendered-ansi,artifacts --crate-type lib <span class="token variable parameter">--emit</span><span class="token operator">=</span>dep-info,metadata,link <span class="token variable parameter">-C</span> opt-level<span class="token operator">=</span><span class="token number">3</span> <span class="token variable parameter">-C</span> embed-bitcode<span class="token operator">=</span>no <span class="token variable parameter">-C</span> <span class="token variable assign-left">metadata</span><span class="token operator">=</span>177d6c810f4d7b82 <span class="token variable parameter">-C</span> extra-filename<span class="token operator">=</span>-177d6c810f4d7b82 --out-dir /home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/deps <span class="token variable parameter">--target</span> x86_64-apple-darwin <span class="token variable parameter">-C</span> <span class="token variable assign-left">linker</span><span class="token operator">=</span>/usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin20.4-clang <span class="token variable parameter">-L</span> <span class="token variable assign-left">dependency</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/deps <span class="token variable parameter">-L</span> <span class="token variable assign-left">dependency</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/release/deps <span class="token variable parameter">--extern</span> <span class="token variable assign-left">libc</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/deps/liblibc-d39c361e04f43fde.rmeta <span class="token variable parameter">--extern</span> <span class="token variable assign-left">libz_sys</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/deps/liblibz_sys-87e6342ea6338869.rmeta --cap-lints allow <span class="token variable parameter">-L</span> <span class="token variable assign-left">native</span><span class="token operator">=</span>/usr/lib <span class="token variable parameter">-l</span> git2 <span class="token variable parameter">-L</span> <span class="token variable assign-left">native</span><span class="token operator">=</span>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/build/libz-sys-cffd7e6d65b74042/out/build<span class="token variable">`</span></span> </span></code></pre></div><p>这一行太长,直接这样看肯定是很难一眼分辨的,因此借助 beyond compare:</p><div><img alt="" src="https://ttys3.dev/static/assets/libgit2-sys-compare-build-command-2021-04-04_01-23-IBPLZ7ND.png" width="3809" height="229"/></div><p>可以很快发现关键区别:</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">arch.log: </span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line">L native=/usr/lib -l git2 </span></span></span><span class="code-line"><span class="token deleted deleted-sign"><span class="token line"></span></span> </span><span class="code-line">ok.log: </span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line">L native=/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/build/libgit2-sys-8d26052ab24e9383/out/build -l static=git2 -l iconv -l framework=Security -l framework=CoreFoundation </span></span></span></code></pre></div><p>可以看到,链接出错的机器,native库的路径不是 libgit2-sys 通过 Darwin toolchain 生成的lib路径,而是使用了系统库的路径(<code>-L native=/usr/lib</code>),然后 libgit2 也没有使用静态链接,而是动态的(<code>-l git2</code>)。</p><p>而正常编译的机器,则是静态链接 (<code>-l static=git2</code>)且静态库的路径指向正确(<code>-L native=/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/build/libgit2-sys-8d26052ab24e9383/out/build</code>)</p><p>我们看下正常的目录结构:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">❯ lsd <span class="token variable parameter">--tree</span> <span class="token variable parameter">--depth</span><span class="token operator">=</span><span class="token number">2</span> /home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/build/libgit2-sys-8d26052ab24e9383/out/build/ </span><span class="code-line"> build </span><span class="code-line">├──  libgit2 </span><span class="code-line">│ ├──  deps </span><span class="code-line">│ └──  src </span><span class="code-line">└──  libgit2.a </span></code></pre></div><p>如果再查看 <code>/home/ttys3/repo/rust/libgit2-demo/target/x86_64-apple-darwin/release/build/libgit2-sys-8d26052ab24e9383/out/build/libgit2/deps</code> 会发现,连依赖都是自带编译的:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"> deps </span><span class="code-line">├──  http-parser </span><span class="code-line">└──  pcre </span></code></pre></div><h2 id="问题产生的真正原因"><a href="#问题产生的真正原因" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>问题产生的真正原因</h2><p>那么在 ArchLinux 下面为什么就编译失败了呢?难道是因为系统已经存在库了?</p><p>一查果然发现,老灯在通过pacman安装 <a href="https://github.com/starship/starship">starship</a> 的时候自动安装了 libgit2 的动态库。</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">❯ pacman <span class="token variable parameter">-Qo</span> /usr/lib/libgit2.so </span><span class="code-line">/usr/lib/libgit2.so is owned by libgit2 <span class="token number">1</span>:1.1.0-1 </span><span class="code-line">❯ <span class="token function">sudo</span> pacman <span class="token variable parameter">-R</span> libgit2 </span><span class="code-line">checking dependencies<span class="token punctuation">..</span>. </span><span class="code-line">error: failed to prepare transaction <span class="token punctuation">(</span>could not satisfy dependencies<span class="token punctuation">)</span> </span><span class="code-line">:: removing libgit2 breaks dependency <span class="token string">&#x27;libgit2.so=1.1-64&#x27;</span> required by starship </span></code></pre></div><p>然后一查 Ubuntu 21.04 beta那边,根本就没有安装这个库。</p><p>于是老灯直接卸载了 <a href="https://github.com/starship/starship">starship</a> 和 libgit2, 发现果然能成功通过编译了。</p><p>问题到这里,好像已经解决了?</p><p>不行,这只是work around, 不是solution.</p><p>注意到前面我们提到 pkg-config-rs 文档中说的 <code>PKG_CONFIG_ALLOW_CROSS=1</code> 在没有恰当地设置的情况下使用,会容易引出链接问题。没错,这次的问题其实就是Makefile中这一句 <code>export PKG_CONFIG_ALLOW_CROSS=1</code>引起的,移除这一行,问题成功解决。</p><p>也就是说,指定 <code>PKG_CONFIG_ALLOW_CROSS=1</code> 时,pkg-config-rs 会在交叉编译时也启用 pkg-config, 而在没有指定交叉编译的target的 pkg-config 路径时, rust 就使用直接了系统(host) 的 pkg-config path了,这个在ArchLinux下面是 <code>/usr/lib/pkgconfig</code>,那么凡是这里能找到的库,它都不会再进行编译了。因此这里出问题时,libgit2-sys实际上没有编译而是直接使用了系统的libgit2.so文件,而这个文件因为是Linux ELF格式的,并不能被交叉编译器所使用。</p><p>如果真的要在交叉编译时启用 pkg-config,则应该指定 <code>/usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin20.4-pkg-config</code>,这个在pkg-config-rs中可以通过 环境变量<code>PKG_CONFIG</code>来设置。PKG_CONFIG_PATH 倒是可以设置。</p><p>环境变量PKG_CONFIG_PATH是用来设置.pc文件的搜索路径的,pkg-config按照设置路径的先后顺序进行搜索,直到找到指定的.pc 文件为止。</p><p>用于指定 <code>pkg-config</code>可执行文件环境变量PKG_CONFIG相关代码:</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token keyword">let</span> exe <span class="token operator">=</span> <span class="token keyword">self</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token string">&quot;PKG_CONFIG&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">unwrap_or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token class-name">OsString</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;pkg-config&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></code></pre></div><p>PKG_CONFIG_ALLOW_CROSS 相关代码:</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token comment">/// Represents all reasons `pkg-config` might not succeed or be run at all.</span> </span><span class="code-line"><span class="token attr-name attribute">#[derive(Debug)]</span> </span><span class="code-line"><span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token class-name type-definition">Error</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">/// Aborted because of `*_NO_PKG_CONFIG` environment variable.</span> </span><span class="code-line"> <span class="token comment">///</span> </span><span class="code-line"> <span class="token comment">/// Contains the name of the responsible environment variable.</span> </span><span class="code-line"> <span class="token class-name">EnvNoPkgConfig</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">/// Detected cross compilation without a custom sysroot.</span> </span><span class="code-line"> <span class="token comment">///</span> </span><span class="code-line"> <span class="token comment">/// Ignore the error with `PKG_CONFIG_ALLOW_CROSS=1`,</span> </span><span class="code-line"> <span class="token comment">/// which may let `pkg-config` select libraries</span> </span><span class="code-line"> <span class="token comment">/// for the host&#x27;s architecture instead of the target&#x27;s.</span> </span><span class="code-line"> <span class="token class-name">CrossCompilation</span><span class="token punctuation">,</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">/// Failed to run `pkg-config`.</span> </span><span class="code-line"> <span class="token comment">///</span> </span><span class="code-line"> <span class="token comment">/// Contains the command and the cause.</span> </span><span class="code-line"> <span class="token class-name">Command</span> <span class="token punctuation">{</span> command<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> cause<span class="token punctuation">:</span> <span class="token namespace">io<span class="token punctuation">::</span></span><span class="token class-name">Error</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">/// `pkg-config` did not exit sucessfully.</span> </span><span class="code-line"> <span class="token comment">///</span> </span><span class="code-line"> <span class="token comment">/// Contains the command and output.</span> </span><span class="code-line"> <span class="token class-name">Failure</span> <span class="token punctuation">{</span> command<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> output<span class="token punctuation">:</span> <span class="token class-name">Output</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token attr-name attribute">#[doc(hidden)]</span> </span><span class="code-line"> <span class="token comment">// please don&#x27;t match on this, we&#x27;re likely to add more variants over time</span> </span><span class="code-line"> __Nonexhaustive<span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">/// Run `pkg-config` to find the library `name`.</span> </span><span class="code-line"> <span class="token comment">///</span> </span><span class="code-line"> <span class="token comment">/// This will use all configuration previously set to specify how</span> </span><span class="code-line"> <span class="token comment">/// `pkg-config` is run.</span> </span><span class="code-line"> <span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function function-definition">probe</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Result</span><span class="token operator">&lt;</span><span class="token class-name">Library</span><span class="token punctuation">,</span> <span class="token class-name">Error</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> abort_var_name <span class="token operator">=</span> <span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{}_NO_PKG_CONFIG&quot;</span><span class="token punctuation">,</span> <span class="token function">envify</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>abort_var_name<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_some</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token class-name">Error</span><span class="token punctuation">::</span><span class="token class-name">EnvNoPkgConfig</span><span class="token punctuation">(</span>abort_var_name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token operator">!</span><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">target_supported</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token class-name">Error</span><span class="token punctuation">::</span><span class="token class-name">CrossCompilation</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> library <span class="token operator">=</span> <span class="token class-name">Library</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">command</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token string">&quot;--libs&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;--cflags&quot;</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span> </span><span class="code-line"> library<span class="token punctuation">.</span><span class="token function">parse_libs_cflags</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token operator">&amp;</span>output<span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">command</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token string">&quot;--modversion&quot;</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span> </span><span class="code-line"> library<span class="token punctuation">.</span><span class="token function">parse_modversion</span><span class="token punctuation">(</span><span class="token keyword">str</span><span class="token punctuation">::</span><span class="token function">from_utf8</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>output<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token class-name">Ok</span><span class="token punctuation">(</span>library<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function function-definition">target_supported</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> target <span class="token operator">=</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var_os</span><span class="token punctuation">(</span><span class="token string">&quot;TARGET&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap_or_default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> host <span class="token operator">=</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var_os</span><span class="token punctuation">(</span><span class="token string">&quot;HOST&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap_or_default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// Only use pkg-config in host == target situations by default (allowing an</span> </span><span class="code-line"> <span class="token comment">// override).</span> </span><span class="code-line"> <span class="token keyword">if</span> host <span class="token operator">==</span> target <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// pkg-config may not be aware of cross-compilation, and require</span> </span><span class="code-line"> <span class="token comment">// a wrapper script that sets up platform-specific prefixes.</span> </span><span class="code-line"> <span class="token keyword">match</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">targetted_env_var</span><span class="token punctuation">(</span><span class="token string">&quot;PKG_CONFIG_ALLOW_CROSS&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// don&#x27;t use pkg-config if explicitly disabled</span> </span><span class="code-line"> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token keyword">ref</span> val<span class="token punctuation">)</span> <span class="token keyword">if</span> val <span class="token operator">==</span> <span class="token string">&quot;0&quot;</span> <span class="token operator">=&gt;</span> <span class="token boolean">false</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token class-name">Some</span><span class="token punctuation">(</span>_<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token class-name">None</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// if not disabled, and pkg-config is customized,</span> </span><span class="code-line"> <span class="token comment">// then assume it&#x27;s prepared for cross-compilation</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">targetted_env_var</span><span class="token punctuation">(</span><span class="token string">&quot;PKG_CONFIG&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_some</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token operator">||</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">targetted_env_var</span><span class="token punctuation">(</span><span class="token string">&quot;PKG_CONFIG_SYSROOT_DIR&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_some</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">targetted_env_var</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> var_base<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Option</span><span class="token operator">&lt;</span><span class="token class-name">OsString</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var</span><span class="token punctuation">(</span><span class="token string">&quot;TARGET&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var</span><span class="token punctuation">(</span><span class="token string">&quot;HOST&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token class-name">Ok</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">Ok</span><span class="token punctuation">(</span>host<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> kind <span class="token operator">=</span> <span class="token keyword">if</span> host <span class="token operator">==</span> target <span class="token punctuation">{</span> <span class="token string">&quot;HOST&quot;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token string">&quot;TARGET&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> target_u <span class="token operator">=</span> target<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">&quot;-&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;_&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{}_{}&quot;</span><span class="token punctuation">,</span> var_base<span class="token punctuation">,</span> target<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{}_{}&quot;</span><span class="token punctuation">,</span> var_base<span class="token punctuation">,</span> target_u<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{}_{}&quot;</span><span class="token punctuation">,</span> kind<span class="token punctuation">,</span> var_base<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span>var_base<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token namespace">env<span class="token punctuation">::</span></span><span class="token class-name">VarError</span><span class="token punctuation">::</span><span class="token class-name">NotPresent</span><span class="token punctuation">)</span><span class="token punctuation">,</span> _<span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token punctuation">(</span>_<span class="token punctuation">,</span> <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token namespace">env<span class="token punctuation">::</span></span><span class="token class-name">VarError</span><span class="token punctuation">::</span><span class="token class-name">NotPresent</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span>var_base<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">(</span><span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token namespace">env<span class="token punctuation">::</span></span><span class="token class-name">VarError</span><span class="token punctuation">::</span><span class="token class-name">NotUnicode</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> _<span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token punctuation">(</span>_<span class="token punctuation">,</span> <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token namespace">env<span class="token punctuation">::</span></span><span class="token class-name">VarError</span><span class="token punctuation">::</span><span class="token class-name">NotUnicode</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">panic!</span><span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;HOST or TARGET environment variable is not valid unicode: {:?}&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> s </span><span class="code-line"> <span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span></code></pre></div><p>也就是说,如果你配置了 <strong>PKG_CONFIG_ALLOW_CROSS=1</strong> 则不管三七二十一,直接不其它加判断,给你使用pkg-config 来找库, 即使在交叉编译到Mac时找到的库是是Linux 格式的。</p><p><code>probe()</code> 通过调用 pkg-config (pkg-config可执行文件路径可通过环境变量配置)来获取include 头包含路径信息和链接库路径信息。</p><p>对于我们的例子来说,如果设置了 LIBGIT2_NO_PKG_CONFIG=1 或 target被判断为不支持pkg-config (交叉编译的情况下,不做任何配置则默认是不支持)就直接不使用pkg-config了。否则就使用pkg-config去找头文件和库.</p><p><code>targetted_env_var() </code>用于支持带 target 的环境变量,同时会默认回退到不带 target 的环境变量。比如 target 是 <code>x86_64-apple-darwin</code> 时,会先后尝试 :</p><ol><li>PKG_CONFIG_ALLOW_CROSS_x86_64-apple-darwin</li><li>PKG_CONFIG_ALLOW_CROSS_x86_64_apple_darwin</li><li>TARGET_PKG_CONFIG_ALLOW_CROSS (非交叉编译时为 HOST_PKG_CONFIG_ALLOW_CROSS)</li><li>PKG_CONFIG_ALLOW_CROSS</li></ol><h2 id="关于是否使用静态链接"><a href="#关于是否使用静态链接" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>关于是否使用静态链接</h2><p>我们看下 libgit2-sys 的 <a href="https://github.com/rust-lang/git2-rs/blob/7912c90991444abb00f9d0476939d48bc368516b/libgit2-sys/build.rs#L13">build.rs 构建脚本</a></p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"> <span class="token keyword">let</span> https <span class="token operator">=</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var</span><span class="token punctuation">(</span><span class="token string">&quot;CARGO_FEATURE_HTTPS&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> ssh <span class="token operator">=</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var</span><span class="token punctuation">(</span><span class="token string">&quot;CARGO_FEATURE_SSH&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> zlib_ng_compat <span class="token operator">=</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var</span><span class="token punctuation">(</span><span class="token string">&quot;CARGO_FEATURE_ZLIB_NG_COMPAT&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// To use zlib-ng in zlib-compat mode, we have to build libgit2 ourselves.</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token operator">!</span>zlib_ng_compat <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// 由于老灯并没有设置 CARGO_FEATURE_ZLIB_NG_COMPAT</span> </span><span class="code-line"> <span class="token comment">// 因此会执行到这里来</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> cfg <span class="token operator">=</span> <span class="token namespace">pkg_config<span class="token punctuation">::</span></span><span class="token class-name">Config</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// 老灯错误地启用了 PKG_CONFIG_ALLOW_CROSS=1 导致 pkg-config-rs </span> </span><span class="code-line"> <span class="token comment">// 错误地返回了 Linux 系统的 libgit2 库</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Ok</span><span class="token punctuation">(</span>lib<span class="token punctuation">)</span> <span class="token operator">=</span> cfg<span class="token punctuation">.</span><span class="token function">atleast_version</span><span class="token punctuation">(</span><span class="token string">&quot;1.1.0&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">probe</span><span class="token punctuation">(</span><span class="token string">&quot;libgit2&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">for</span> include <span class="token keyword">in</span> <span class="token operator">&amp;</span>lib<span class="token punctuation">.</span>include_paths <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">println!</span><span class="token punctuation">(</span><span class="token string">&quot;cargo:root={}&quot;</span><span class="token punctuation">,</span> include<span class="token punctuation">.</span><span class="token function">display</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword">return</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span></code></pre></div><p>可以看到 pkg_config::Config::new() 使用了 pkg-config-rs 的默认配置,我们看下默认配置是什么样的:</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"><span class="token comment">/// Creates a new set of configuration options which are all initially set</span> </span><span class="code-line"> <span class="token comment">/// to &quot;blank&quot;.</span> </span><span class="code-line"> <span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function function-definition">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Config</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name">Config</span> <span class="token punctuation">{</span> </span><span class="code-line"> statik<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span> </span><span class="code-line"> min_version<span class="token punctuation">:</span> <span class="token class-name">Bound</span><span class="token punctuation">::</span><span class="token class-name">Unbounded</span><span class="token punctuation">,</span> </span><span class="code-line"> max_version<span class="token punctuation">:</span> <span class="token class-name">Bound</span><span class="token punctuation">::</span><span class="token class-name">Unbounded</span><span class="token punctuation">,</span> </span><span class="code-line"> extra_args<span class="token punctuation">:</span> <span class="token property macro">vec!</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> </span><span class="code-line"> print_system_cflags<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> print_system_libs<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> cargo_metadata<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> env_metadata<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> </span></code></pre></div><p>没错,默认是<code> statik: None</code> 也就是默认是动态链接的。</p><p>那那些 static 连接参数是怎么生成的呢?</p><p><code>is_static()</code> 先判断配置,如果配置是 false, 则会继续进行 infer 推断. 以libgit2 为例:</p><p>若 <code>LIBGIT2_STATIC=1</code> 则启用静态</p><p>若 <code>LIBGIT2_DYNAMIC=1</code> 则启用动态</p><p>若 <code>PKG_CONFIG_ALL_STATIC=1</code> 则启用静态</p><p>若 <code>PKG_CONFIG_ALL_DYNAMIC=1</code> 则启用动态</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">is_static</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span>statik<span class="token punctuation">.</span><span class="token function">unwrap_or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">infer_static</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">infer_static</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> name <span class="token operator">=</span> <span class="token function">envify</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{}_STATIC&quot;</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_some</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token boolean">true</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;{}_DYNAMIC&quot;</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_some</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token boolean">false</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token string">&quot;PKG_CONFIG_ALL_STATIC&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_some</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token boolean">true</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token string">&quot;PKG_CONFIG_ALL_DYNAMIC&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_some</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token boolean">false</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token boolean">false</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span></code></pre></div><p>执行pkg-config 的时候会根据 <code>is_static() </code>的结果传递 <code>--static</code> 参数给pkg-config:</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">command</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span> args<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Command</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> exe <span class="token operator">=</span> <span class="token keyword">self</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token string">&quot;PKG_CONFIG&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">unwrap_or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token class-name">OsString</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;pkg-config&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> cmd <span class="token operator">=</span> <span class="token class-name">Command</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span>exe<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">is_static</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> cmd<span class="token punctuation">.</span><span class="token function">arg</span><span class="token punctuation">(</span><span class="token string">&quot;--static&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> cmd<span class="token punctuation">.</span><span class="token function">args</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">args</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">.</span>extra_args<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// ... </span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>最终生成的是 <code>rustc-link-lib=static=xxxx</code> :</p><div class="relative"><pre><code class="code-highlight language-rust"><span class="code-line"> <span class="token keyword">fn</span> <span class="token function function-definition">parse_libs_cflags</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span> output<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token keyword">u8</span><span class="token punctuation">]</span><span class="token punctuation">,</span> config<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">Config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> is_msvc <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Ok</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token namespace">env<span class="token punctuation">::</span></span><span class="token function">var</span><span class="token punctuation">(</span><span class="token string">&quot;TARGET&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> target<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token string">&quot;msvc&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> is_msvc <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">let</span> system_roots <span class="token operator">=</span> <span class="token keyword">if</span> <span class="token property macro">cfg!</span><span class="token punctuation">(</span>target_os <span class="token operator">=</span> <span class="token string">&quot;macos&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">vec!</span><span class="token punctuation">[</span><span class="token class-name">PathBuf</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;/Library&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">PathBuf</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;/System&quot;</span><span class="token punctuation">)</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> sysroot <span class="token operator">=</span> config </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token string">&quot;PKG_CONFIG_SYSROOT_DIR&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> config<span class="token punctuation">.</span><span class="token function">env_var_os</span><span class="token punctuation">(</span><span class="token string">&quot;SYSROOT&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token class-name">PathBuf</span><span class="token punctuation">::</span>from<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token property macro">cfg!</span><span class="token punctuation">(</span>target_os <span class="token operator">=</span> <span class="token string">&quot;windows&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>sysroot<span class="token punctuation">)</span> <span class="token operator">=</span> sysroot <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">vec!</span><span class="token punctuation">[</span>sysroot<span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">vec!</span><span class="token punctuation">[</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">vec!</span><span class="token punctuation">[</span>sysroot<span class="token punctuation">.</span><span class="token function">unwrap_or_else</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span><span class="token punctuation closure-punctuation">|</span></span> <span class="token class-name">PathBuf</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;/usr&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> dirs <span class="token operator">=</span> <span class="token class-name">Vec</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">let</span> statik <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">is_static</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">let</span> words <span class="token operator">=</span> <span class="token function">split_flags</span><span class="token punctuation">(</span>output<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// Handle single-character arguments like `-I/usr/include`</span> </span><span class="code-line"> <span class="token keyword">let</span> parts <span class="token operator">=</span> words </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>l<span class="token punctuation closure-punctuation">|</span></span> l<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">2</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>arg<span class="token punctuation closure-punctuation">|</span></span> <span class="token punctuation">(</span><span class="token operator">&amp;</span>arg<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">..</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>arg<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">..</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">(</span>flag<span class="token punctuation">,</span> val<span class="token punctuation">)</span> <span class="token keyword">in</span> parts <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">match</span> flag <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;-L&quot;</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> meta <span class="token operator">=</span> <span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;rustc-link-search=native={}&quot;</span><span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> config<span class="token punctuation">.</span><span class="token function">print_metadata</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>meta<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> dirs<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token class-name">PathBuf</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span>link_paths<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token class-name">PathBuf</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token string">&quot;-F&quot;</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> meta <span class="token operator">=</span> <span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;rustc-link-search=framework={}&quot;</span><span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> config<span class="token punctuation">.</span><span class="token function">print_metadata</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>meta<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span>framework_paths<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token class-name">PathBuf</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token string">&quot;-I&quot;</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span>include_paths<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token class-name">PathBuf</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token string">&quot;-l&quot;</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// These are provided by the CRT with MSVC</span> </span><span class="code-line"> <span class="token keyword">if</span> is_msvc <span class="token operator">&amp;&amp;</span> <span class="token punctuation">[</span><span class="token string">&quot;m&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;c&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;pthread&quot;</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>val<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">continue</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">if</span> statik <span class="token operator">&amp;&amp;</span> <span class="token function">is_static_available</span><span class="token punctuation">(</span>val<span class="token punctuation">,</span> <span class="token operator">&amp;</span>system_roots<span class="token punctuation">,</span> <span class="token operator">&amp;</span>dirs<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> meta <span class="token operator">=</span> <span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;rustc-link-lib=static={}&quot;</span><span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> config<span class="token punctuation">.</span><span class="token function">print_metadata</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>meta<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> meta <span class="token operator">=</span> <span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;rustc-link-lib={}&quot;</span><span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> config<span class="token punctuation">.</span><span class="token function">print_metadata</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>meta<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span>libs<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>val<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token string">&quot;-D&quot;</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> iter <span class="token operator">=</span> val<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token char">&#x27;=&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span>defines<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span> </span><span class="code-line"> iter<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">to_owned</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> iter<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>s<span class="token punctuation closure-punctuation">|</span></span> s<span class="token punctuation">.</span><span class="token function">to_owned</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> _ <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// Handle multi-character arguments with space-separated value like `-framework foo`</span> </span><span class="code-line"> <span class="token keyword">let</span> <span class="token keyword">mut</span> iter <span class="token operator">=</span> words<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flat_map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token punctuation closure-punctuation">|</span>arg<span class="token punctuation closure-punctuation">|</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> arg<span class="token punctuation">.</span><span class="token function">starts_with</span><span class="token punctuation">(</span><span class="token string">&quot;-Wl,&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> arg<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">..</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token char">&#x27;,&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property macro">vec!</span><span class="token punctuation">[</span>arg<span class="token punctuation">.</span><span class="token function">as_ref</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">while</span> <span class="token keyword">let</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>part<span class="token punctuation">)</span> <span class="token operator">=</span> iter<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">match</span> part <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;-framework&quot;</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>lib<span class="token punctuation">)</span> <span class="token operator">=</span> iter<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> meta <span class="token operator">=</span> <span class="token property macro">format!</span><span class="token punctuation">(</span><span class="token string">&quot;rustc-link-lib=framework={}&quot;</span><span class="token punctuation">,</span> lib<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> config<span class="token punctuation">.</span><span class="token function">print_metadata</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>meta<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span>frameworks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>lib<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token string">&quot;-isystem&quot;</span> <span class="token operator">|</span> <span class="token string">&quot;-iquote&quot;</span> <span class="token operator">|</span> <span class="token string">&quot;-idirafter&quot;</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>inc<span class="token punctuation">)</span> <span class="token operator">=</span> iter<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">self</span><span class="token punctuation">.</span>include_paths<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token class-name">PathBuf</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span>inc<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> _ <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>## Refs</p><p><a href="https://doc.rust-lang.org/cargo/reference/build-scripts.html">https://doc.rust-lang.org/cargo/reference/build-scripts.html</a></p><p><a href="https://github.com/rust-lang/git2-rs/blob/7912c90991444abb00f9d0476939d48bc368516b/libgit2-sys/build.rs#L13">https://github.com/rust-lang/git2-rs/blob/7912c90991444abb00f9d0476939d48bc368516b/libgit2-sys/build.rs#L13</a></p><p><a href="https://doc.rust-lang.org/cargo/reference/config.html#target">https://doc.rust-lang.org/cargo/reference/config.html#target</a></p><p><a href="https://wapl.es/rust/2019/02/17/rust-cross-compile-linux-to-macos.html">https://wapl.es/rust/2019/02/17/rust-cross-compile-linux-to-macos.html</a></p><p><a href="https://docs.rs/pkg-config/0.3.19/pkg_config/">https://docs.rs/pkg-config/0.3.19/pkg_config/</a></p><p><a href="https://github.com/rust-lang/git2-rs">https://github.com/rust-lang/git2-rs</a></p> Sat, 03 Apr 2021 15:05:06 GMT ttyS3 https://ttys3.dev/blog/how-to-start-tmux-as-systemd-user-service How To Start Tmux as Systemd User Service https://ttys3.dev/blog/how-to-start-tmux-as-systemd-user-service <p>tmux 启动一下能有多慢?答案是,挺快的。 那为什么要有这种需求? 原因是布局恢复。 老灯目前使用的是一个tpm插件,名叫 <code>tmux-resurrect</code>, prefix + ctrl + r 即可自动恢复所有panel.</p><p>但是有个小问题,panel比较多,比如有10多个的情况下,启动tmux还是会小闪一下的,整个过程肉眼可见,</p><p>会造成操作上的停顿。比如你打开 Gnome terminal 马上就能执行命令了,但是你刚开机启动tmux,你得等几秒才能操作,就因为这个panel恢复。</p><p>怎么样加快这个过程?答案当然是,用户登录的时候就马上运行tmux呗。</p><p>这个比较简单,直接看 ArchLinux 的 wiki 整个 systemd unit 文件就好了。</p><p>不过 Arch 的 wiki 有个小错误。</p><p><code>/etc/systemd/system/[email protected]</code></p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Unit</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Description</span><span class="token punctuation">=</span><span class="token attr-value value">Start tmux in detached session</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Service</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Type</span><span class="token punctuation">=</span><span class="token attr-value value">forking</span> </span><span class="code-line"><span class="token attr-name key">User</span><span class="token punctuation">=</span><span class="token attr-value value">%I</span> </span><span class="code-line"><span class="token comment"># 这里 Arch wiki 原来写的是 %u, 应该修正为 %i</span> </span><span class="code-line"><span class="token attr-name key">ExecStart</span><span class="token punctuation">=</span><span class="token attr-value value">/usr/bin/tmux new-session -s %i -d</span> </span><span class="code-line"><span class="token attr-name key">ExecStop</span><span class="token punctuation">=</span><span class="token attr-value value">/usr/bin/tmux kill-session -t %i</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Install</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">WantedBy</span><span class="token punctuation">=</span><span class="token attr-value value">multi-user.target</span> </span></code></pre></div><p>要使用 <code>%i</code>(表示 instance, 即 tmux@<code>xxx</code>.service 里的 <code>xxx</code>) 而不是<code>%u</code></p><p>的原因是: <code>%u</code> 的值并不会被 <code>User=</code> 配置所影响,它表示的是 the name of the <em>user running the service manager instance ,</em> 由于 Arch wiki 里用的是system级的unit文件,因此实际上用户名是 root</p><table><thead><tr><th>Specifier</th><th>Meaning</th><th>Details</th></tr></thead><tbody><tr><td>&quot;<code>%u</code>&quot;</td><td>User name</td><td>This is the name of the <em>user running the service manager instance</em>. In case of the system manager this resolves to &quot;<code>root</code>&quot;. Note that this setting is <em>not</em> influenced by the <code>User=</code> setting configurable in the [Service] section of the service unit.</td></tr><tr><td>&quot;<code>%i</code>&quot;</td><td>Instance name</td><td>For instantiated units this is the string between the first &quot;<code>@</code>&quot; character and the type suffix. Empty for non-instantiated units.</td></tr><tr><td>&quot;<code>%I</code>&quot;</td><td>Unescaped instance name</td><td>Same as &quot;<code>%i</code>&quot;, but with escaping undone.</td></tr></tbody></table><p>老灯还是觉得 user service 在这种场景下更为合适,因此没有采用 system 级别的 service方案。</p><p>我的 <code>mytmux.service</code> 内容如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment"># put this file to ~/.config/systemd/user/mytmux.service</span> </span><span class="code-line"><span class="token comment"># enable the service: systemctl --user enable mytmux</span> </span><span class="code-line"><span class="token comment"># ref https://wiki.archlinux.org/index.php/Tmux#Autostart_with_systemd</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Unit</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Description</span><span class="token punctuation">=</span><span class="token attr-value value">Start tmux in detached session</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Service</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Type</span><span class="token punctuation">=</span><span class="token attr-value value">forking</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># comment here, use zsh preexec instead</span> </span><span class="code-line"><span class="token comment"># below must changed per host/user</span> </span><span class="code-line"><span class="token comment"># Environment=DISPLAY=:1</span> </span><span class="code-line"><span class="token comment"># Environment=XAUTHORITY=/run/user/1000/gdm/Xauthority</span> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">ExecStart</span><span class="token punctuation">=</span><span class="token attr-value value">/usr/bin/tmux new-session -s %u -d</span> </span><span class="code-line"><span class="token attr-name key">ExecStop</span><span class="token punctuation">=</span><span class="token attr-value value">/usr/bin/tmux kill-session -t %u</span> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">Restart</span><span class="token punctuation">=</span><span class="token attr-value value">on-failure</span> </span><span class="code-line"><span class="token attr-name key">RestartSec</span><span class="token punctuation">=</span><span class="token attr-value value">3s</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Install</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">WantedBy</span><span class="token punctuation">=</span><span class="token attr-value value">default.target</span> </span></code></pre></div><p>为方便安装,整了个 <code>Makefile</code>:</p><div class="relative"><pre><code class="code-highlight language-makefile"><span class="code-line"><span class="token symbol target">install</span><span class="token punctuation">:</span> </span><span class="code-line"> -systemctl --user stop mytmux 2&gt;/dev/null </span><span class="code-line"> install -vD -m 755 ./mytmux.service ~/.config/systemd/user/mytmux.service </span><span class="code-line"> systemctl --user daemon-reload </span><span class="code-line"> systemctl --user enable --now mytmux </span><span class="code-line"> systemctl --user status mytmux </span><span class="code-line"> journalctl --user -a -f -u mytmux </span><span class="code-line"><span class="token builtin builtin-target">.PHONY</span><span class="token punctuation">:</span> install </span></code></pre></div><h2 id="troubleshooting"><a href="#troubleshooting" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>troubleshooting</h2><h3 id="1-display-环境变量没有被设置"><a href="#1-display-环境变量没有被设置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. DISPLAY 环境变量没有被设置</h3><p>这里指的是从 <code>tmux-resurrect</code> 自动恢复的panel里的zsh进程没有获取到 DISPLAY 环境变量,但是如果你在那个panel使用<code>tmux showenv</code>查看,却发现tmux本身是获取到了这个变量的,只是 zsh 没有获取到。</p><p>猜测应该是 user service 启动的时候,x11 其实并没有完成启动。而 tmux 自身之所以能获取到 DISPLAY 的值,是因为它会自动刷新。(如果不刷新,可以通过设置 <code>set -g update-environment &#x27;DISPLAY SSH_ASKPASS SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY TERM&#x27;</code> 修复 )</p><p>几经折腾后,在<a href="https://babushk.in/posts/renew-environment-tmux.html">这里</a>找到了答案。在<code>.zshrc</code> 中加上 <code>preexec</code> hook 即可:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token keyword control-flow">if</span> <span class="token punctuation">[</span> <span class="token operator">-</span>n <span class="token string">&quot;$TMUX&quot;</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> then </span><span class="code-line"> <span class="token keyword">function</span> refresh_env_var_from_systemd_started_tmux <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword module">export</span> <span class="token function">$</span><span class="token punctuation">(</span>tmux show<span class="token operator">-</span>environment <span class="token operator">|</span> grep <span class="token string">&quot;^DISPLAY&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword module">export</span> <span class="token function">$</span><span class="token punctuation">(</span>tmux show<span class="token operator">-</span>environment <span class="token operator">|</span> grep <span class="token string">&quot;^XAUTHORITY&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token keyword control-flow">else</span> </span><span class="code-line"> <span class="token keyword">function</span> refresh_env_var_from_systemd_started_tmux <span class="token punctuation">{</span> <span class="token punctuation">}</span> </span><span class="code-line">fi </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">function</span> preexec <span class="token punctuation">{</span> </span><span class="code-line"> refresh_env_var_from_systemd_started_tmux </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>注意这里一定要用 <code>preexec</code> hook,直接执行 <code>refresh_env_var_from_systemd_started_tmux</code> 是没有效果的,</p><p>因为执行的时候,DISPLAY 还是空的呢。</p><p>另外有一点不要误解的就是,<code>set-option -g update-environment</code> 这里的update是针对 tmux 进程自身的,</p><p>而不是通过 tmux 启动的 shell (比如 zsh).</p><p>还有一种比较笨的方法就是直接在 systemd unit 文件中指定这些环境变量的值,比如:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token attr-name key">Environment</span><span class="token punctuation">=</span><span class="token attr-value value">DISPLAY=:1</span> </span><span class="code-line"><span class="token attr-name key">Environment</span><span class="token punctuation">=</span><span class="token attr-value value">XAUTHORITY=/run/user/1000/gdm/Xauthority</span> </span></code></pre></div><p>为什么需要这个?有些程序(一般是x11 client)的运行是要依赖<code>DISPLAY</code>这个环境变量的,比如 <code>https://github.com/suxpert/vimcaps</code> 这个vim插件, 里面有个c lib, 初始化的时候就会调用 <code>XOpenDisplay</code></p><h3 id="2-tmuxservice-user-service-重启后被奇怪地禁用了"><a href="#2-tmuxservice-user-service-重启后被奇怪地禁用了" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. tmux.service user service 重启后被奇怪地禁用了</h3><p>这个其实是老灯装了一个叫 <code>tmux-continuum</code> 的tpm插件的锅。这个问题确实坑了我很久。</p><p>我怎么想到这一点的?我刚开始并没想到,并且重启了n次,折腾了好久,被这货害惨了。</p><p>后面我把 <code>tmux.service</code> 改成了 <code>mytmux.service</code> 发现问题神奇的消失了。</p><p>症状就是: <code>systemctl --user enable tmux</code> 后,明明服务成功运行了,检查 <code>~/.config/systemd/user/default.target.wants/tmux.service</code> 也是存在的,说明确实成功<code>enable</code>了。</p><p>一重启,发现<code>~/.config/systemd/user/default.target.wants/tmux.service</code> 已经消失了。服务自动是被禁用状态了。</p><p><code>tmux-continuum/scripts/variables.sh</code> 中有定义: <code>systemd_service_name=&quot;tmux.service&quot;</code></p><p>然后这货在tmux启动时会执行 <code>systemctl --user disable ${systemd_service_name}</code></p><p>见 <code>tmux-continuum/scripts/handle_tmux_automatic_start.sh</code></p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function function-name">is_tmux_automatic_start_enabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">local</span> <span class="token variable assign-left">auto_start_value</span><span class="token operator">=</span><span class="token string">&quot;<span class="token variable"><span class="token variable">$(</span>get_tmux_option <span class="token string">&quot;<span class="token variable">$auto_start_option</span>&quot;</span> <span class="token string">&quot;<span class="token variable">$auto_start_default</span>&quot;</span><span class="token variable">)</span></span>&quot;</span> </span><span class="code-line"> <span class="token punctuation">[</span> <span class="token string">&quot;<span class="token variable">$auto_start_value</span>&quot;</span> <span class="token operator">==</span> <span class="token string">&quot;on&quot;</span> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"><span class="token function function-name">is_osx</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token punctuation">[</span> <span class="token variable"><span class="token variable">$(</span><span class="token function">uname</span><span class="token variable">)</span></span> <span class="token operator">==</span> <span class="token string">&quot;Darwin&quot;</span> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">is_systemd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token punctuation">[</span> <span class="token variable"><span class="token variable">$(</span><span class="token function">ps</span> <span class="token variable parameter">-o</span> <span class="token variable assign-left">comm</span><span class="token operator">=</span> <span class="token variable parameter">-p1</span><span class="token variable">)</span></span> <span class="token operator">==</span> <span class="token string">&#x27;systemd&#x27;</span> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> is_tmux_automatic_start_enabled<span class="token punctuation">;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token keyword">if</span> is_osx<span class="token punctuation">;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token string">&quot;<span class="token variable">$CURRENT_DIR</span>/handle_tmux_automatic_start/osx_enable.sh&quot;</span> </span><span class="code-line"> <span class="token keyword">elif</span> is_systemd<span class="token punctuation">;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token string">&quot;<span class="token variable">$CURRENT_DIR</span>/handle_tmux_automatic_start/systemd_enable.sh&quot;</span> </span><span class="code-line"> <span class="token keyword">fi</span> </span><span class="code-line"> <span class="token keyword">else</span> </span><span class="code-line"> <span class="token keyword">if</span> is_osx<span class="token punctuation">;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token string">&quot;<span class="token variable">$CURRENT_DIR</span>/handle_tmux_automatic_start/osx_disable.sh&quot;</span> </span><span class="code-line"> <span class="token keyword">elif</span> is_systemd<span class="token punctuation">;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token string">&quot;<span class="token variable">$CURRENT_DIR</span>/handle_tmux_automatic_start/systemd_disable.sh&quot;</span> </span><span class="code-line"> <span class="token keyword">fi</span> </span><span class="code-line"> <span class="token keyword">fi</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line">main </span></code></pre></div><p>默认配置是这样的:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">auto_start_option<span class="token operator">=</span><span class="token string">&quot;@continuum-boot&quot;</span> </span><span class="code-line">auto_start_default<span class="token operator">=</span><span class="token string">&quot;off&quot;</span> </span></code></pre></div><p>所以每次重启后就执行了<code>&quot;$CURRENT_DIR/handle_tmux_automatic_start/systemd_disable.sh&quot;</code></p><p>即 <code>systemctl --user disable tmux.service</code></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://github.com/tmux-plugins/tmux-resurrect">https://github.com/tmux-plugins/tmux-resurrect</a></p><p><a href="https://github.com/tmux-plugins/tmux-continuum">https://github.com/tmux-plugins/tmux-continuum</a></p><p><a href="https://wiki.archlinux.org/index.php/tmux#Autostart_with_systemd">https://wiki.archlinux.org/index.php/tmux#Autostart_with_systemd</a></p><p><a href="https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers">https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers</a></p><p><a href="https://babushk.in/posts/renew-environment-tmux.html">https://babushk.in/posts/renew-environment-tmux.html</a></p><p><a href="https://goosebearingbashshell.github.io/2017/12/07/reset-display-variable-in-tmux.html">https://goosebearingbashshell.github.io/2017/12/07/reset-display-variable-in-tmux.html</a></p> Tue, 30 Mar 2021 19:27:29 GMT ttyS3 tmuxsystemdx11 https://ttys3.dev/blog/how-to-switch-capslock-with-escape-in-linux How To Switch Caps Lock with Escape in Linux https://ttys3.dev/blog/how-to-switch-capslock-with-escape-in-linux <p>Window: X11 DE: GNOME3 OS: ArchLinux</p><p>为什么会有这种需求? 当然是 vim 用户才有这种需求。</p><h2 id="setxkbmap大法"><a href="#setxkbmap大法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>setxkbmap大法</h2><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">setxkbmap <span class="token parameter variable">-option</span> caps:swapescape </span></code></pre></div><p><strong>To make this work at startup</strong>, you can put it in <code>~/.profile</code> as this will only run after the interactive login.</p><h2 id="gnome-tweak大法"><a href="#gnome-tweak大法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a><strong>gnome-tweak大法</strong></h2><p>对于GNOME用户来说,最简单省事的方法当然是使用 <strong>gnome-tweak</strong></p><div><img alt="" src="https://ttys3.dev/static/assets/gnome-tweak-tool-switch-caps-esc-2021-03-31_03-13-YXOHJVLF.png" width="1576" height="1037"/></div><p>通过gnome tweak设置,实际上相当于执行了:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">gsettings <span class="token builtin class-name">set</span> org.gnome.desktop.input-sources xkb-options <span class="token string">&quot;[&#x27;caps:swapescape&#x27;]&quot;</span> </span></code></pre></div><p>当前值可通过get获取:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ gsettings get org.gnome.desktop.input-sources xkb-options </span><span class="code-line"><span class="token punctuation">[</span><span class="token string">&#x27;lv3:ralt_switch&#x27;</span>, <span class="token string">&#x27;caps:swapescape&#x27;</span><span class="token punctuation">]</span> </span></code></pre></div><h2 id="xkb-rules-大法"><a href="#xkb-rules-大法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>xkb rules 大法</h2><p>新建一 <code>/etc/X11/xorg.conf.d/90-custom-kbd.conf</code></p><p>内容大致如下:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token maybe-class-name">Section</span> <span class="token string">&quot;InputClass&quot;</span> </span><span class="code-line"> <span class="token maybe-class-name">Identifier</span> <span class="token string">&quot;system-keyboard&quot;</span> </span><span class="code-line"> <span class="token maybe-class-name">MatchIsKeyboard</span> <span class="token string">&quot;on&quot;</span> </span><span class="code-line"> <span class="token maybe-class-name">Option</span> <span class="token string">&quot;XkbLayout&quot;</span> <span class="token string">&quot;us&quot;</span> </span><span class="code-line"> <span class="token maybe-class-name">Option</span> <span class="token string">&quot;XkbModel&quot;</span> <span class="token string">&quot;pc104&quot;</span> </span><span class="code-line"> <span class="token maybe-class-name">Option</span> <span class="token string">&quot;XkbOptions&quot;</span> <span class="token string">&quot;caps:swapescape&quot;</span> </span><span class="code-line"><span class="token maybe-class-name">EndSection</span> </span></code></pre></div><h2 id="xmodmap大法"><a href="#xmodmap大法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>xmodmap大法</h2><p>最古老的方法应该是 xmodmap 大法吧,这也是最容易找到答案的。但是这应该是老灯最不推荐的方法了,因此放到最后。</p><p><code>~/.Xmodmap</code> 内容如下:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">clear <span class="token maybe-class-name">Lock</span> </span><span class="code-line">keysym <span class="token maybe-class-name">Caps_Lock</span> <span class="token operator">=</span> <span class="token maybe-class-name">Escape</span> </span><span class="code-line">keysym <span class="token maybe-class-name">Escape</span> <span class="token operator">=</span> <span class="token maybe-class-name">Caps_Lock</span> </span><span class="code-line">add <span class="token maybe-class-name">Lock</span> <span class="token operator">=</span> <span class="token maybe-class-name">Caps_Lock</span> </span></code></pre></div><p>然后开机后执行: <code>xmodmap ~/.Xmodmap</code></p><p>文档上说 GDM 会自动执行这个,不需要手动干预执行,但是老灯测试,实际上 GNOME3.38 并不会执行这个。</p><p>see <a href="https://bugzilla.redhat.com/show_bug.cgi?id=873656">https://bugzilla.redhat.com/show_bug.cgi?id=873656</a></p><p><a href="https://blogs.gnome.org/sudaltsov/2010/10/13/xmodmap-and-gnome/">这个文章</a> 也确认了这一点。也就是说差不多10年前这个就不会自动load了。</p><blockquote><p>October 13, 2010 11:20 pm Sergey Udaltsov GNOME (gnome-settings-daemon) was supporting custom xmodmap files for ages – as a convenient way to tweak the kbd config. I heard several times about people using that feature – even though it was never important, used by minority. <strong>Yesterday that feature has gone from g-s-d</strong>.</p></blockquote><h2 id="troubleshooting"><a href="#troubleshooting" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>troubleshooting</h2><p><code>xkb-options</code> 不工作?</p><p>可能你使用的是较老版本的有bug的GNOME, 比如 Ubuntu 20.04 with gnome-shell <code>3.36.4-1ubuntu1~20.04.2</code></p><p>fixed in 3.38 (see <a href="https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3299#note_977234">https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3299#note_977234</a> )</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Refs</h2><p><a href="https://blogs.gnome.org/sudaltsov/2010/10/13/xmodmap-and-gnome/">https://blogs.gnome.org/sudaltsov/2010/10/13/xmodmap-and-gnome/</a></p><p><a href="https://bugzilla.redhat.com/show_bug.cgi?id=873656">https://bugzilla.redhat.com/show_bug.cgi?id=873656</a></p><p><a href="https://gitlab.gnome.org/GNOME/gnome-tweaks/-/issues/50">https://gitlab.gnome.org/GNOME/gnome-tweaks/-/issues/50</a></p><p><a href="https://askubuntu.com/questions/363346/how-to-permanently-switch-caps-lock-and-esc">https://askubuntu.com/questions/363346/how-to-permanently-switch-caps-lock-and-esc</a></p><p><a href="https://wiki.archlinux.org/index.php/xmodmap#Custom_table">https://wiki.archlinux.org/index.php/xmodmap#Custom_table</a></p><p><a href="https://superuser.com/questions/566871/how-to-map-the-caps-lock-key-to-escape-key-in-arch-linux/1239550#1239550">https://superuser.com/questions/566871/how-to-map-the-caps-lock-key-to-escape-key-in-arch-linux/1239550#1239550</a></p><p><a href="https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3299">https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3299</a></p><p><a href="https://wiki.archlinux.org/index.php/X_keyboard_extension#Using_rules">https://wiki.archlinux.org/index.php/X_keyboard_extension#Using_rules</a></p> Tue, 30 Mar 2021 18:52:37 GMT ttyS3 x11capslockescapeGNOME https://ttys3.dev/blog/got-my-first-apc-ups 买了个APC UPS https://ttys3.dev/blog/got-my-first-apc-ups <p>今天回到家已经很晚了,一到家发现 NAS 是关机的, PC 按电源也没反应。</p><p>然后 发现 山特 mt 1000 pro UPS 灯是灭的。</p><p>几经折腾还是不能开机,没有一个灯亮的。查了一下狗东订单,这款 mt1000 pro大概是2018年12月入的。</p><p>点击申请售后,提示已经过保。但是商品页面写着3年保修(但是狗东保修那里没填写任何东西),24小时客服热线啊(大晚上估计没客服,也不抱什么希望了)。</p><p>手里还有个 山特 tg500,结果一试,发现也点不亮了。这下好了,俩 UPS 全挂。</p><p>当初买这款mt1000 pro,主要是看重它支持通过 rs232 串口来查询状态和控制断电自启选项。用 Golang 自己写了个程序,可以实现市电断了之后 NAS 自动关机 (网上找的文档,协议和功能都非常简单)。</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line">类型:后备式 </span><span class="code-line">品牌:山特(<span class="token constant">STK</span>) </span><span class="code-line">额定容量:<span class="token number">600</span> 瓦数 <span class="token operator">/</span> <span class="token number">1000</span> <span class="token constant">VA</span> </span><span class="code-line">产品尺寸(mm):<span class="token number">84</span><span class="token operator">*</span><span class="token number">430</span><span class="token operator">*</span>220MM </span><span class="code-line">输入电压:<span class="token number">173</span><span class="token operator">~</span><span class="token number">273</span><span class="token function"><span class="token maybe-class-name">VAC</span></span><span class="token punctuation">(</span>标准模式<span class="token punctuation">)</span> </span></code></pre></div><p>比较窄,但是超级长(43cm),我只能将它对角放在机柜,直接放会多出来10多厘米。</p><p>22cm 高是我这个机柜的极限了(随便买的一个放东西的架子,估且称作机柜吧,毕竟现在就是当机柜用)。</p><p>需求:带一台高性能的 PC + 8盘位 NAS, 因此 群辉NAS好基友 -- <code>APC BK650-CH</code> 或它的新款 <code>APC BK650M2-CH</code> 这种 <code>390W / 650 VA</code> 的可能满足不了需求。</p><p><code>BR1000G-CN</code>(价格1300¥ 左右) 同样是<code>600W/1000VA</code>,支持 NAS 自动关机和来电自启, 但是25cm的高度我这放不下(382mm<em>100mm</em>250mm)</p><p><code>BX1100CI-CN</code> 带有AVR, <code>660W/1100VA</code>, 没有通知功能。狗东最近活动价 700 左右。</p><p><code>BP1000CH</code>(价格570¥左右) 同样是<code>600W/1000VA</code>,性价比高啊。 不过 320mm<em>130mm</em>182mm 的尺寸我这刚好可放下。另外还带 rs232 接口可以通知 PC 自动关机。</p><p>综合对比之下,BP1000CH 是个不错的选择,虽然机型可能有点老。但是 BP1000CH 跟其它型号有一个非常重大的区别,就是:它在电池模式输出的波形是 <code>方波</code>, 而现在大部分流行的家用 UPS 都是 <code>正弦波逐步逼近</code> s (step-approximated sinewave)</p><blockquote><p>UPS 电源按其工作方式可分为后备式 UPS 和在线式 UPS 两大类; 而按其输出波形又可分为方波输出 UPS 和正弦波输出 UPS 两种。</p></blockquote><p>根据网上<a href="http://ups16888.com/pdf/zixun/yuanli.pdf">不知名的资料</a>:</p><blockquote><p>方波输出的 UPS 电源带负载能力差(负载量仅为额定负载的 40~ 60%),不能带电感性负载。如所带的负载过大,方波输出电压中包 含的三次谐波成份将使流入负载中的容性电流增大,严重时会损坏负 载的电源滤波电容。 正弦波输出的 UPS 电源的输出电压波形畸变度与负载量之间的 关系没有方波输出 UPS 电源那样明显,带负载能力相对较强,并能带 微电感性负载。</p></blockquote><p>所以,老灯最终还是选择了 <a href="https://www.apc.com/shop/cn/zh/products/Back-UPS-1100VA-AVR-230V/P-BX1100CI-CN">BX1100CI-CN</a></p><p><a href="https://www.apc.com/shop/cn/zh/products/APC-Back-UPS-1000VA-/P-BP1000CH">https://www.apc.com/shop/cn/zh/products/APC-Back-UPS-1000VA-/P-BP1000CH</a></p><p><a href="https://www.apc.com/shop/cn/zh/products/Back-UPS-1100VA-AVR-230V/P-BX1100CI-CN">https://www.apc.com/shop/cn/zh/products/Back-UPS-1100VA-AVR-230V/P-BX1100CI-CN</a></p> Thu, 25 Mar 2021 19:04:15 GMT ttyS3 https://ttys3.dev/blog/go-rsa-private-encrypt-and-public-decrypt Golang RSA 如何私钥加密公钥解密 https://ttys3.dev/blog/go-rsa-private-encrypt-and-public-decrypt <p>一般来说,加密主要用于消息的传递,并且传递的消息只有持有私钥的那个人能解密。</p><p>因此, 像 RSA 这种非对称密钥加密算法的常用场景是:</p><p>对于加密,公钥加密,私钥解密。</p><p>为什么不是 私钥加密,公钥解密呢? 因为使用场景是假定 公钥 都可以获取到,因而公钥解密这种操作也就与明文无异了。</p><p>有没有私钥加密的常用场景呢?当然是有,比如常见的签名操作。</p><p>明文消息 -&gt; 进行 hash -&gt; 对 hash 后的结果进行私钥加密, 这个加密后的结果就是签名了。</p><p>对签名进行验证实际上就是用公钥解密,然后把解密后的hash与原始消息的hash进行对比。</p><p>客户端:明文消息 -&gt; 进行 hash -&gt; 对签名使用公钥进行解密,并对比 hash 结果。</p><h2 id="the-story"><a href="#the-story" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>the story</h2><p>早期版本的 Go 标准库 并不提供私钥加密 和 公钥解密功能。但是大家应该能猜想到,</p><p>其实要实现 私钥加密, 只需要在原来的签名函数上修改一个 hash 参数,使得这个 hash 啥也不做。</p><p>当然,由于明文并不能像 hash 一样是固定位数 的,因此,这里自然免不了要 padding.</p><p>Go 的 签名是采用的 PKCS #1 v1.5 padding 方式。</p><p>这个提交使得标准库直接支持 私钥加密了:</p><p><a href="https://github.com/golang/go/commit/78c16c9b16dc9c64d1ddad6db5afaab12e87e8f2#diff-fd7abb32dfad4ffb52bb17669ce4a8a4114917e7d4a055107a9f1fc9381f1c94R233">https://github.com/golang/go/commit/78c16c9b16dc9c64d1ddad6db5afaab12e87e8f2#diff-fd7abb32dfad4ffb52bb17669ce4a8a4114917e7d4a055107a9f1fc9381f1c94R233</a></p><blockquote><p>crypto/rsa: support unpadded signatures.</p><p>Usually when a message is signed it&#x27;s first hashed because RSA has low limits on the size of messages that it can sign. However, some protocols sign short messages directly. This isn&#x27;t a great idea because the messages that can be signed suddenly depend on the size of the RSA key, but several people on golang-nuts have requested support for this and it&#x27;s very easy to do.</p><p>R=golang-codereviews, rsc CC=golang-codereviews golang.org/cl/44400043</p></blockquote><h2 id="the-solution"><a href="#the-solution" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>the solution</h2><p>Since go <code>1.3</code>, you can easily do this using <code>SignPKCS1v15</code></p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">rsa<span class="token punctuation">.</span><span class="token function method property-access"><span class="token maybe-class-name">SignPKCS1v15</span></span><span class="token punctuation">(</span>nil<span class="token punctuation">,</span> priv<span class="token punctuation">,</span> crypto<span class="token punctuation">.</span><span class="token function method property-access"><span class="token maybe-class-name">Hash</span></span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> plainData<span class="token punctuation">)</span> </span></code></pre></div><p>refer:  <a href="https://groups.google.com/forum/#!topic/Golang-Nuts/Vocj33WNhJQ">https://groups.google.com/forum/#!topic/Golang-Nuts/Vocj33WNhJQ</a></p><p>所以,现在的 <code>SignPKCS1v15</code> 方法是这样的:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// SignPKCS1v15 calculates the signature of hashed using</span> </span><span class="code-line"><span class="token comment">// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS #1 v1.5. Note that hashed must</span> </span><span class="code-line"><span class="token comment">// be the result of hashing the input message using the given hash</span> </span><span class="code-line"><span class="token comment">// function. If hash is zero, hashed is signed directly. This isn&#x27;t</span> </span><span class="code-line"><span class="token comment">// advisable except for interoperability.</span> </span><span class="code-line"><span class="token comment">//</span> </span><span class="code-line"><span class="token comment">// If rand is not nil then RSA blinding will be used to avoid timing</span> </span><span class="code-line"><span class="token comment">// side-channel attacks.</span> </span><span class="code-line"><span class="token comment">//</span> </span><span class="code-line"><span class="token comment">// This function is deterministic. Thus, if the set of possible</span> </span><span class="code-line"><span class="token comment">// messages is small, an attacker may be able to build a map from</span> </span><span class="code-line"><span class="token comment">// messages to signatures and identify the signed messages. As ever,</span> </span><span class="code-line"><span class="token comment">// signatures provide authenticity, not confidentiality.</span> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">SignPKCS1v15</span><span class="token punctuation">(</span>rand io<span class="token punctuation">.</span>Reader<span class="token punctuation">,</span> priv <span class="token operator">*</span>PrivateKey<span class="token punctuation">,</span> hash crypto<span class="token punctuation">.</span>Hash<span class="token punctuation">,</span> hashed <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">byte</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">byte</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> hashLen<span class="token punctuation">,</span> prefix<span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">pkcs1v15HashInfo</span><span class="token punctuation">(</span>hash<span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>hashed<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> err </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> tLen <span class="token operator">:=</span> <span class="token function">len</span><span class="token punctuation">(</span>prefix<span class="token punctuation">)</span> <span class="token operator">+</span> hashLen </span><span class="code-line"> k <span class="token operator">:=</span> priv<span class="token punctuation">.</span><span class="token function">Size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> k <span class="token operator">&lt;</span> tLen<span class="token operator">+</span><span class="token number">11</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> ErrMessageTooLong </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// EM = 0x00 || 0x01 || PS || 0x00 || T</span> </span><span class="code-line"> em <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">byte</span><span class="token punctuation">,</span> k<span class="token punctuation">)</span> </span><span class="code-line"> em<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">2</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> k<span class="token operator">-</span>tLen<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> i<span class="token operator">++</span> <span class="token punctuation">{</span> </span><span class="code-line"> em<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">0xff</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token function">copy</span><span class="token punctuation">(</span>em<span class="token punctuation">[</span>k<span class="token operator">-</span>tLen<span class="token punctuation">:</span>k<span class="token operator">-</span>hashLen<span class="token punctuation">]</span><span class="token punctuation">,</span> prefix<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token function">copy</span><span class="token punctuation">(</span>em<span class="token punctuation">[</span>k<span class="token operator">-</span>hashLen<span class="token punctuation">:</span>k<span class="token punctuation">]</span><span class="token punctuation">,</span> hashed<span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> m <span class="token operator">:=</span> <span class="token function">new</span><span class="token punctuation">(</span>big<span class="token punctuation">.</span>Int<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">SetBytes</span><span class="token punctuation">(</span>em<span class="token punctuation">)</span> </span><span class="code-line"> c<span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">decryptAndCheck</span><span class="token punctuation">(</span>rand<span class="token punctuation">,</span> priv<span class="token punctuation">,</span> m<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> err </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">return</span> c<span class="token punctuation">.</span><span class="token function">FillBytes</span><span class="token punctuation">(</span>em<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">nil</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>如果给 rand 传 nil 则每次生成的加密结果都是一样的。</p><p>如果给 crypto.Hash() 传0, 则表示不进行任何 hash</p><p>因此,私钥加密实际上只是一个特殊参数的调用:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line">encrypted<span class="token punctuation">,</span> err <span class="token operator">:=</span> rsa<span class="token punctuation">.</span><span class="token function">SignPKCS1v15</span><span class="token punctuation">(</span><span class="token boolean">nil</span><span class="token punctuation">,</span> priv<span class="token punctuation">,</span> crypto<span class="token punctuation">.</span><span class="token function">Hash</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token function">byte</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span> </span></code></pre></div><h2 id="troubleshoot"><a href="#troubleshoot" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>troubleshoot</h2><p>Golang 加密后的消息给 node.js 解密时,node.js 报错:</p><blockquote><p>rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01</p></blockquote><p>不要被错误信息迷惑了。这种错误跟 block type (padding) 没有什么关系。</p><p>错误的根本原因是,要么是加密的人私钥用错了,要么是解密的人公钥用错了。(没错,我在写某知名软件的注册机时,因为这个错误提示浪费了很多时间 ,直到后面意识到了问题的真正原因。 另外,我还要在这里吐槽一下某公司,你们的注册算法写得太烂了,有标准的签名算法不用,直接用的私钥加密/公钥解密这一套。还害我写这么一篇文章 。另外,都2021年了,你们还在用 RSA 1024)</p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://golang.org/src/crypto/rsa/pkcs1v15.go?s=8774:8874#L221">https://golang.org/src/crypto/rsa/pkcs1v15.go?s=8774:8874#L221</a></p><p><a href="https://gist.github.com/kkHAIKE/be3b8d7ff8886457c6fdac2714d56fe1">https://gist.github.com/kkHAIKE/be3b8d7ff8886457c6fdac2714d56fe1</a></p><p><a href="https://github.com/buf1024/golib/blob/master/crypt/rsa.go">https://github.com/buf1024/golib/blob/master/crypt/rsa.go</a></p><p><a href="https://topic.alibabacloud.com/a/golang-private-key-encrypt-public-key-decrypt_1_38_30920103.html">https://topic.alibabacloud.com/a/golang-private-key-encrypt-public-key-decrypt_1_38_30920103.html</a></p><p>node.js 类似 <a href="https://www.geeksforgeeks.org/node-js-crypto-publicdecrypt-method/">https://www.geeksforgeeks.org/node-js-crypto-publicdecrypt-method/</a></p><p><a href="https://github.com/nodejs/help/issues/1093">https://github.com/nodejs/help/issues/1093</a></p> Sun, 21 Mar 2021 16:14:38 GMT ttyS3 gorsaencryption https://ttys3.dev/blog/neovim-cpu-stuck-on-100-percent-issue-debug NeoVim CPU Stuck on 100% issue debug https://ttys3.dev/blog/neovim-cpu-stuck-on-100-percent-issue-debug <p>最近发现打开某些行数“超级多”的古老 go 代码时,自动完成 和 保存 的时候都很卡,卡到什么程度呢? 完全无法正常使用的程度。</p><h2 id="保存文件时-cpu-100"><a href="#保存文件时-cpu-100" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>保存文件时 CPU 100%</h2><p>先说下 文件保存 的时候的卡顿问题吧。</p><p>这个问题经过排查主要是 Ale 插件引起的。</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token keyword">let</span> <span class="token literal-property property">g</span><span class="token operator">:</span>ale_fixers <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line">\ <span class="token string">&#x27;*&#x27;</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">&#x27;remove_trailing_lines&#x27;</span><span class="token punctuation">,</span> <span class="token string">&#x27;trim_whitespace&#x27;</span><span class="token punctuation">]</span><span class="token punctuation">,</span> </span><span class="code-line">\ <span class="token string">&#x27;go&#x27;</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">&#x27;gofmt&#x27;</span><span class="token punctuation">,</span> <span class="token string">&#x27;goimports&#x27;</span><span class="token punctuation">]</span><span class="token punctuation">,</span> </span><span class="code-line">\<span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">let</span> <span class="token literal-property property">g</span><span class="token operator">:</span>ale_fix_on_save <span class="token operator">=</span> <span class="token number">1</span> </span></code></pre></div><p>这个配置会使 ale 在 go 文件保存的时候自动执行 gofmt 和 goimports fixer</p><p>触发问题的go文件大概有1万行代码左右。</p><p>6 核心 4.0 GHz 9代 CPU, 卡顿时间 大概是 60s.</p><p>问题点可以用vim自带的 profile 找出:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token operator">:</span>profile start ale<span class="token punctuation">.</span><span class="token property-access">log</span> </span><span class="code-line"><span class="token operator">:</span>profile file <span class="token operator">*</span> </span><span class="code-line"><span class="token operator">:</span>profile func <span class="token operator">*</span> </span><span class="code-line"><span class="token operator">:</span>e foo<span class="token punctuation">.</span><span class="token property-access">go</span> </span><span class="code-line"><span class="token operator">:</span>q </span></code></pre></div><p>profile 结果:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token constant">FUNCTIONS</span> <span class="token constant">SORTED</span> <span class="token constant">ON</span> <span class="token constant">TOTAL</span> <span class="token constant">TIME</span> </span><span class="code-line">count <span class="token function">total</span> <span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token function">self</span> <span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token keyword">function</span> </span><span class="code-line"> <span class="token number">6</span> <span class="token number">95.284024</span> <span class="token number">0.000682</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">131</span><span class="token function">_NeoVimCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">3</span> <span class="token number">95.219276</span> <span class="token number">0.001431</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">128</span><span class="token function">_ExitCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">2</span> <span class="token number">95.205686</span> <span class="token number">0.051308</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">149</span><span class="token function">_HandleExit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">3</span> <span class="token number">95.158971</span> <span class="token number">0.000787</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">149</span><span class="token function">_RunFixer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">1</span> <span class="token number">95.148690</span> <span class="token number">0.003005</span> ale#fix<span class="token function">#ApplyFixes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">1</span> <span class="token number">95.145444</span> <span class="token number">0.008286</span> ale#fix<span class="token function">#ApplyQueuedFixes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">1</span> <span class="token number">95.124312</span> <span class="token number">95.124310</span> ale#util<span class="token function">#SetBufferContents</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">11</span> <span class="token number">0.628545</span> <span class="token number">0.003539</span> scrollview<span class="token function">#HandleMouse</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">11</span> <span class="token number">0.618689</span> <span class="token number">0.617861</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_ReadInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">410</span> <span class="token number">0.312603</span> <span class="token number">0.005017</span> <span class="token function"><span class="token maybe-class-name">CapsStatusline</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">410</span> <span class="token number">0.307586</span> <span class="token number">0.037893</span> vimcaps<span class="token function">#statusline</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">410</span> <span class="token number">0.269693</span> <span class="token number">0.266351</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">110</span><span class="token function">_lockstate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">5</span> <span class="token number">0.187795</span> <span class="token number">0.000137</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_RefreshBarsAsyncCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">5</span> <span class="token number">0.187657</span> <span class="token number">0.000680</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_RefreshBars</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">5</span> <span class="token number">0.185126</span> <span class="token number">0.062890</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_ShowScrollbar</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">5</span> <span class="token number">0.120451</span> <span class="token number">0.002321</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_CalculatePosition</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">10</span> <span class="token number">0.116327</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_VirtualLineCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">3</span> <span class="token number">0.063975</span> <span class="token number">0.047837</span> ale#util<span class="token function">#JoinNeovimOutput</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">205</span> <span class="token number">0.061899</span> <span class="token number">0.005964</span> <span class="token function"><span class="token maybe-class-name">AleStatus</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">4</span> <span class="token number">0.032224</span> <span class="token number">0.000098</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">79</span><span class="token function">_on_refresh_event</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token constant">FUNCTIONS</span> <span class="token constant">SORTED</span> <span class="token constant">ON</span> <span class="token constant">SELF</span> <span class="token constant">TIME</span> </span><span class="code-line">count <span class="token function">total</span> <span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token function">self</span> <span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token keyword">function</span> </span><span class="code-line"> <span class="token number">1</span> <span class="token number">95.124312</span> <span class="token number">95.124310</span> ale#util<span class="token function">#SetBufferContents</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">11</span> <span class="token number">0.618689</span> <span class="token number">0.617861</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_ReadInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">410</span> <span class="token number">0.269693</span> <span class="token number">0.266351</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">110</span><span class="token function">_lockstate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">10</span> <span class="token number">0.116327</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_VirtualLineCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">5</span> <span class="token number">0.185126</span> <span class="token number">0.062890</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">142</span><span class="token function">_ShowScrollbar</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">2</span> <span class="token number">95.205686</span> <span class="token number">0.051308</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">149</span><span class="token function">_HandleExit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">3</span> <span class="token number">0.063975</span> <span class="token number">0.047837</span> ale#util<span class="token function">#JoinNeovimOutput</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">410</span> <span class="token number">0.307586</span> <span class="token number">0.037893</span> vimcaps<span class="token function">#statusline</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">4</span> <span class="token number">0.032126</span> <span class="token number">0.031659</span> hexokinase#v2#scraper<span class="token function">#on</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">7</span> <span class="token number">0.020110</span> <span class="token number">0.019948</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">110</span><span class="token function">_toggleoff</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token number">10428</span> <span class="token number">0.016139</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">128</span><span class="token function">_GatherOutput</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">410</span> <span class="token number">0.014748</span> <span class="token function"><span class="token maybe-class-name">LspStatus</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">615</span> <span class="token number">0.013326</span> <span class="token function"><span class="token maybe-class-name">LightlineFilename</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">410</span> <span class="token number">0.013600</span> <span class="token number">0.012902</span> <span class="token function"><span class="token maybe-class-name">ClapFilterImplStatusLine</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">812</span> <span class="token number">0.019331</span> <span class="token number">0.011470</span> <span class="token operator">&lt;</span><span class="token constant">SNR</span><span class="token operator">&gt;</span><span class="token number">147</span><span class="token function">_GetCounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">3</span> <span class="token number">0.011297</span> <span class="token number">0.011285</span> ale#job<span class="token function">#Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">1032</span> <span class="token number">0.009730</span> ale#engine<span class="token function">#IsCheckingBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">205</span> <span class="token number">0.008788</span> lightline<span class="token function">#link</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">820</span> <span class="token number">0.015992</span> <span class="token number">0.008526</span> lightline#ale<span class="token function">#linted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token number">1</span> <span class="token number">95.145444</span> <span class="token number">0.008286</span> ale#fix<span class="token function">#ApplyQueuedFixes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span></code></pre></div><p><a href="https://github.com/dense-analysis/ale/issues/3634">提给官方</a>了, 作者很快回复了,真的是佩服作者这认真态度。</p><p>作者提示说,将 <code>foldmethod=syntax</code> 改成 <code>foldmethod=indent</code> 性能会好很多:</p><blockquote><p>A fix for this was attempted in <a href="https://github.com/dense-analysis/ale/pull/3358">#3358</a>, but caused <a href="https://github.com/dense-analysis/ale/issues/3504">#3504</a>, so we reverted it in <a href="https://github.com/dense-analysis/ale/pull/3535">#3535</a>. I&#x27;m interested in seeing a fix for this that doesn&#x27;t cause the same cursor position jumping issue.</p><p>One thing you can try is not using syntax folding if you&#x27;re using folding, or switching to folding based on indentation, because folds tend to ruin the performance of setting lines in Vim.</p></blockquote><p>后来我修改 <code>foldmethod=syntax</code> 发现卡顿时间 确实是少了很多,从原来 60s 左右 降低到 15s 以下了。</p><p>但是问题还是存在,暂时来说这个 issue 还没有解决。</p><p>后面我禁用了ale 自动修复功能 ( <code>let g:ale_fix_on_save = 0</code> ), 然后使用neovim 自带的 lsp format 和 codeAction 来执行自动 format 和 import 修复。</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line">autocmd <span class="token maybe-class-name">BufWritePre</span> <span class="token operator">*</span><span class="token punctuation">.</span><span class="token property-access">go</span> lua vim<span class="token punctuation">.</span><span class="token property-access">lsp</span><span class="token punctuation">.</span><span class="token property-access">buf</span><span class="token punctuation">.</span><span class="token function property-access method">formatting_sync</span><span class="token punctuation">(</span>nil<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span> </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line"> <span class="token keyword">function</span> <span class="token function">goimports</span><span class="token punctuation">(</span>timeoutms<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">local</span> context <span class="token operator">=</span> <span class="token punctuation">{</span> source <span class="token operator">=</span> <span class="token punctuation">{</span> organizeImports <span class="token operator">=</span> <span class="token keyword">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span><span class="code-line"> vim<span class="token punctuation">.</span><span class="token function">validate</span> <span class="token punctuation">{</span> context <span class="token operator">=</span> <span class="token punctuation">{</span> context<span class="token punctuation">,</span> <span class="token string">&quot;t&quot;</span><span class="token punctuation">,</span> <span class="token keyword">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">local</span> params <span class="token operator">=</span> vim<span class="token punctuation">.</span>lsp<span class="token punctuation">.</span>util<span class="token punctuation">.</span><span class="token function">make_range_params</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> params<span class="token punctuation">.</span>context <span class="token operator">=</span> context </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">-- See the implementation of the textDocument/codeAction callback</span> </span><span class="code-line"> <span class="token comment">-- (lua/vim/lsp/handler.lua) for how to do this properly.</span> </span><span class="code-line"> <span class="token keyword">local</span> result <span class="token operator">=</span> vim<span class="token punctuation">.</span>lsp<span class="token punctuation">.</span><span class="token function">buf_request_sync</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">&quot;textDocument/codeAction&quot;</span><span class="token punctuation">,</span> params<span class="token punctuation">,</span> timeout_ms<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">not</span> result <span class="token keyword">or</span> <span class="token function">next</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">nil</span> <span class="token keyword">then</span> <span class="token keyword">return</span> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">local</span> actions <span class="token operator">=</span> result<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>result </span><span class="code-line"> <span class="token keyword">if</span> <span class="token keyword">not</span> actions <span class="token keyword">then</span> <span class="token keyword">return</span> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">local</span> action <span class="token operator">=</span> actions<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">-- textDocument/codeAction can return either Command[] or CodeAction[]. If it</span> </span><span class="code-line"> <span class="token comment">-- is a CodeAction, it can have either an edit, a command or both. Edits</span> </span><span class="code-line"> <span class="token comment">-- should be executed first.</span> </span><span class="code-line"> <span class="token keyword">if</span> action<span class="token punctuation">.</span>edit <span class="token keyword">or</span> <span class="token function">type</span><span class="token punctuation">(</span>action<span class="token punctuation">.</span>command<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token string">&quot;table&quot;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token keyword">if</span> action<span class="token punctuation">.</span>edit <span class="token keyword">then</span> </span><span class="code-line"> vim<span class="token punctuation">.</span>lsp<span class="token punctuation">.</span>util<span class="token punctuation">.</span><span class="token function">apply_workspace_edit</span><span class="token punctuation">(</span>action<span class="token punctuation">.</span>edit<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token function">type</span><span class="token punctuation">(</span>action<span class="token punctuation">.</span>command<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token string">&quot;table&quot;</span> <span class="token keyword">then</span> </span><span class="code-line"> vim<span class="token punctuation">.</span>lsp<span class="token punctuation">.</span>buf<span class="token punctuation">.</span><span class="token function">execute_command</span><span class="token punctuation">(</span>action<span class="token punctuation">.</span>command<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">else</span> </span><span class="code-line"> vim<span class="token punctuation">.</span>lsp<span class="token punctuation">.</span>buf<span class="token punctuation">.</span><span class="token function">execute_command</span><span class="token punctuation">(</span>action<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"> <span class="token keyword">end</span> </span><span class="code-line"> </span><span class="code-line">vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_command</span><span class="token punctuation">(</span><span class="token string">&#x27;autocmd BufWritePre *.go lua goimports(1000)&#x27;</span><span class="token punctuation">)</span> </span></code></pre></div><p>另外提一句: gopls 已经内置了 <a href="https://github.com/mvdan/gofumpt"><code>gofumpt</code></a> 支持了, 配置 <code>gofumpt = true</code> 即可,老灯的配置如下:</p><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line"><span class="token comment">--@param client: (required, vim.lsp.client)</span> </span><span class="code-line"><span class="token keyword">local</span> mix_attach <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&#x27;lsp-status&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on_attach</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&#x27;completion&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on_attach</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&#x27;illuminate&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on_attach</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span> </span><span class="code-line"><span class="token keyword">end</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">-- lsp.gopls.setup{}</span> </span><span class="code-line"><span class="token comment">-- https://github.com/neovim/nvim-lspconfig/blob/master/lua/lspconfig/gopls.lua</span> </span><span class="code-line"><span class="token comment">-- https://github.com/golang/tools/blob/master/gopls/doc/vim.md#neovim</span> </span><span class="code-line"><span class="token comment">-- https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#gopls</span> </span><span class="code-line">lsp<span class="token punctuation">.</span>gopls<span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">{</span> </span><span class="code-line"> on_attach <span class="token operator">=</span> mix_attach<span class="token punctuation">,</span> </span><span class="code-line"> settings <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> gopls <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> usePlaceholders <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">,</span> </span><span class="code-line"> completeUnimported <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">,</span> </span><span class="code-line"> allowModfileModifications <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">,</span> </span><span class="code-line"> allowImplicitNetworkAccess <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">,</span> </span><span class="code-line"> usePlaceholders <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token comment">-- https://github.com/golang/tools/blob/master/gopls/doc/settings.md#gofumpt-bool</span> </span><span class="code-line"> <span class="token comment">-- https://github.com/mvdan/gofumpt/commit/38fc491470bae6f44e2d38b06277dd95cf1bdf97</span> </span><span class="code-line"> <span class="token comment">-- https://go-review.googlesource.com/c/tools/+/241985/7/gopls/internal/hooks/hooks.go#22</span> </span><span class="code-line"> gofumpt <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> capabilities <span class="token operator">=</span> lsp_status<span class="token punctuation">.</span>capabilities<span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span> </span></code></pre></div><h2 id="自动完成或保存时-cpu-100"><a href="#自动完成或保存时-cpu-100" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>自动完成或保存时 CPU 100%</h2><p>这个问题排查了我很久,排查了很久的原因是,问题代码在 lua 调用 treesitter 的相关代码里。</p><p>直接用 vim 自带的 profile 没法找到影响性能的问题点。</p><p>另一个原因是,当时的 nvim lsp 也有 CPU 性能问题,大文件会导致 CPU 100%, 但是二者的情况不同。</p><p>nvim lsp 导致 CPU 100% 时 CPU 会很快恢复正常 Load, 而 <a href="https://github.com/p00f/nvim-ts-rainbow">p00f/nvim-ts-rainbow</a> 引起的则不会。</p><p>当然,导致我排查了这很久,主要原因还是自己想当然,压根没有考虑到是 treesitter 相关的插件引起的。</p><p>因为这个 rainbow 配置成启用也就一行 <code>rainbow = { enable = false, },</code> 而已。</p><p>用最小配置来测试,然后把怀疑有问题的插件加进来。当然,最后还是定位到原因了,那就是由<a href="https://github.com/p00f/nvim-ts-rainbow">p00f/nvim-ts-rainbow</a> 引起的。当然,我不是第一个发现这个问题的。别人早就提了: <a href="https://github.com/p00f/nvim-ts-rainbow/issues/5">https://github.com/p00f/nvim-ts-rainbow/issues/5</a></p><p>当然,我也在这个 issue 下面回复了一下。但是这个作者并不鸟我, 倒是同样遇到这个问题的另一个用户 还 专门 跑到我的另一个 issue 回复我了。</p><p>当初切到这个 ts 版的 raibow 是因为 <code>luochen1990/rainbow</code> 与 nvim ts 有兼容性问题需要 hack 处理。</p><p>当 nvim CPU 100% 时,很久都不能恢复(几十秒以上)。此时如果强行 kill 掉 nvim 会在终端看到一大堆类似如下错误:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token class-name known-class-name">Error</span> executing vim<span class="token punctuation">.</span><span class="token property-access">schedule</span> lua callback<span class="token operator">:</span> <span class="token operator">/</span>usr<span class="token operator">/</span>local<span class="token operator">/</span>share<span class="token operator">/</span>nvim<span class="token operator">/</span>runtime<span class="token operator">/</span>lua<span class="token operator">/</span>vim<span class="token operator">/</span>treesitter<span class="token operator">/</span>query<span class="token punctuation">.</span><span class="token property-access">lua</span><span class="token operator">:</span><span class="token number">135</span><span class="token operator">:</span> bad argument #<span class="token number">1</span> to <span class="token string">&#x27;get_node_text&#x27;</span> <span class="token punctuation">(</span>string expected<span class="token punctuation">,</span> got nil<span class="token punctuation">)</span> </span></code></pre></div><p>切回 vimL 版的 <code>luochen1990/rainbow</code>:</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token maybe-class-name">Plug</span> <span class="token string">&#x27;luochen1990/rainbow&#x27;</span> </span><span class="code-line"><span class="token keyword">let</span> <span class="token literal-property property">g</span><span class="token operator">:</span>rainbow_active <span class="token operator">=</span> <span class="token number">1</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">lua <span class="token operator">&lt;&lt;</span><span class="token constant">EOF</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token operator">--</span> fixup nvim<span class="token operator">-</span>treesitter cause luochen1990<span class="token operator">/</span>rainbow not working problem </span><span class="code-line"><span class="token operator">--</span> see https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>github<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>nvim<span class="token operator">-</span>treesitter<span class="token operator">/</span>nvim<span class="token operator">-</span>treesitter<span class="token operator">/</span>issues<span class="token operator">/</span><span class="token number">123</span>#issuecomment<span class="token operator">-</span><span class="token number">651162962</span> </span><span class="code-line"><span class="token operator">--</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>github<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>nvim<span class="token operator">-</span>treesitter<span class="token operator">/</span>nvim<span class="token operator">-</span>treesitter<span class="token operator">/</span>issues<span class="token operator">/</span><span class="token number">654</span>#issuecomment<span class="token operator">-</span><span class="token number">727562988</span> </span><span class="code-line"><span class="token operator">--</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>github<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>luochen1990<span class="token operator">/</span>rainbow<span class="token operator">/</span>issues<span class="token operator">/</span><span class="token number">151</span>#issuecomment<span class="token operator">-</span><span class="token number">677644891</span> </span><span class="code-line">require <span class="token string">&quot;nvim-treesitter.highlight&quot;</span> </span><span class="code-line"><span class="token operator">--</span> vim<span class="token punctuation">.</span><span class="token property-access"><span class="token maybe-class-name">TSHighlighter</span></span> is removed<span class="token punctuation">,</span> please use vim<span class="token punctuation">.</span><span class="token property-access">treesitter</span><span class="token punctuation">.</span><span class="token property-access">highlighter</span> </span><span class="code-line"><span class="token operator">--</span> see https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>github<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>neovim<span class="token operator">/</span>neovim<span class="token operator">/</span>pull<span class="token operator">/</span><span class="token number">14145</span><span class="token operator">/</span>commits<span class="token operator">/</span>b5401418768af496ef23b790f700a44b61ad784d </span><span class="code-line"><span class="token operator">--</span> deactivate highlight <span class="token keyword">of</span> <span class="token maybe-class-name">TSPunctBracket</span> </span><span class="code-line">local hlmap <span class="token operator">=</span>vim<span class="token punctuation">.</span><span class="token property-access">treesitter</span><span class="token punctuation">.</span><span class="token property-access">highlighter</span><span class="token punctuation">.</span><span class="token property-access">hl_map</span> </span><span class="code-line">hlmap<span class="token punctuation">.</span><span class="token property-access">error</span> <span class="token operator">=</span> nil </span><span class="code-line">hlmap<span class="token punctuation">[</span><span class="token string">&quot;punctuation.delimiter&quot;</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">&quot;Delimiter&quot;</span> </span><span class="code-line">hlmap<span class="token punctuation">[</span><span class="token string">&quot;punctuation.bracket&quot;</span><span class="token punctuation">]</span> <span class="token operator">=</span> nil </span><span class="code-line"> </span><span class="code-line"><span class="token constant">EOF</span> </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://github.com/golang/tools/blob/master/gopls/doc/vim.md#neovim-imports">https://github.com/golang/tools/blob/master/gopls/doc/vim.md#neovim-imports</a></p><p><a href="https://github.com/golang/tools/blob/master/gopls/doc/settings.md#gofumpt-bool">https://github.com/golang/tools/blob/master/gopls/doc/settings.md#gofumpt-bool</a></p><p><a href="https://github.com/mvdan/gofumpt/commit/38fc491470bae6f44e2d38b06277dd95cf1bdf97">https://github.com/mvdan/gofumpt/commit/38fc491470bae6f44e2d38b06277dd95cf1bdf97</a></p><p><a href="https://go-review.googlesource.com/c/tools/+/241985/7/gopls/internal/hooks/hooks.go#22">https://go-review.googlesource.com/c/tools/+/241985/7/gopls/internal/hooks/hooks.go#22</a></p><p><a href="https://github.com/p00f/nvim-ts-rainbow/issues/5">https://github.com/p00f/nvim-ts-rainbow/issues/5</a></p><p><a href="https://github.com/dense-analysis/ale/issues/3634">https://github.com/dense-analysis/ale/issues/3634</a></p> Sun, 21 Mar 2021 15:30:21 GMT ttyS3 neovimvimcpu-stuckperformance https://ttys3.dev/blog/the-storey-of-swoole-and-fiber 2021 年 PHP 界 Swoole 和 Fiber 的那些瓜 https://ttys3.dev/blog/the-storey-of-swoole-and-fiber <p>我是在知乎上偶然看到这么个瓜。</p><p>rfc 投票地址: <a href="https://wiki.php.net/rfc/fibers">https://wiki.php.net/rfc/fibers</a></p><p>内部讨论记录: <a href="https://externals.io/message/113430">https://externals.io/message/113430</a></p><p>在 rfc 投票地址 地址上老灯看到有 46 票通过, 13票反对。 我们去 <a href="https://wiki.php.net/rfc/fibers">https://wiki.php.net/rfc/fibers</a> 看看这 13 票反对的都是哪些人。</p><p><a href="https://github.com/krakjoe/parallel">parallel的作者</a> krakjoe 反对是可以理解的,人家直言希望自己的扩展被合并成内核,而不是 Fiber.</p><p>至于rasmus (Rasmus Lerdorf,PHP 创始人) 吧,我觉得现在版本的 PHP 开发应该跟他没什么关系了,他说啥都行,高兴就好。</p><p>所以,13反对票里,有3个是 Swoole 相关方面 的人,有一个甚至还是 Swoole 的创始人。</p><ul><li>doubaokun Swoole开发者</li><li>tianfenghan Swoole开发者, Rango(韩天峰)</li><li>twosee Swoole开发者,Twosee(陈曹奇昊)</li></ul><p>老灯的观点与知乎上某些观点比较一致:</p><blockquote><p>拒绝提案的理由是没有做到完善?我觉得这个站不住脚,不能说这个提案目前没有像 Swoole 一样弄一整套就不合并吧?(难道只有 Swoole 这种整套的才行?)</p><p>另一个理由是,普通开发者用不上,只有amphp 和 reactphp 这类项目用得上?这我觉得也站不住脚。你永远不知道用户能创造出什么框架出来。以 Go 语言为例, unsafe 代码普通人都用不上, 那 Go 就不用支持 unsafe 了?感觉这些理由很“主观”和“自以为是”。</p></blockquote><p>老灯就两个提问摘取一些回答围观:</p><p>《<a href="https://www.zhihu.com/question/448805077">如何看待Swoole作者声称Fiber提案对非Amp以外的项目毫无价值?</a>》</p><p>老外对于这个说法也是相当的不happy的,见 <a href="https://www.reddit.com/r/PHP/comments/m1w32y/maintainer_of_swoole_about_the_fibers_rfc_i_am/">https://www.reddit.com/r/PHP/comments/m1w32y/maintainer_of_swoole_about_the_fibers_rfc_i_am/</a></p><p>作者:鲁严波<br/>链接:<a href="https://www.zhihu.com/question/448805077/answer/1778652091%5C">https://www.zhihu.com/question/448805077/answer/1778652091\</a> 来源:知乎<br/>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p><p>看了一圈,大家都是在讨论PHP和Swoole,但在回答这个问题之前,我们需要了解一下背景。</p><p><strong>1协程的出现</strong></p><p>摩尔定律逐步失效,多线程编程开始流行。</p><p>然后多线程世界中的开发者(比如C++、Java开发者)发现了两件事情:</p><p>第一,多线程写代码还是很蛋疼,需要考虑互斥、同步,很容易出现海森堡bug。</p><p>第二,多线程也不是万灵药,在IO密集场景下,线程调度成为了多线程的瓶颈。</p><p>发现了这些问题后。开发人员(重新)捡起了协程这个概念。</p><p>协程对于不支持多线程的语言(比如PHP)或者多线程支持不太好的语言(嗯,Python的GIL)都是一个机会。</p><p>本来支持多线程要做很多改造,从内核到C扩展都需要配合改造。现在好了,一步到位,直接进入协程时代。</p><p>但是协程,也出现了两个流派:</p><p><strong>1.1无栈协程</strong></p><p>JS的ayncio、python官方的asyncio、这次PHP的generator都是此类代表。</p><p>特点就是,<strong>协程切换是手动触发</strong>,从而免除了大部分互斥的操作(没有yield就不会被切换,那就基本没有互斥了)</p><p>但是很显然,上面的方案中除了JS的async发展起来了,其他的都不是很流行。</p><p>这就要说到他们的缺点了,需要改代码。</p><p>一旦底层框架使用了无栈协程,上层都要跟着改造。比如底层一个协程yield一个generator/promise,那么上层就要yield这个generator/promise,一直到顶层的协程调度器来处理这个generator/promise。</p><p>站在广大程序员的角度,事情变得很复杂了:</p><p><em>我就把DB driver改成了异步的,你就要我把DAO层、业务逻辑层、Web渲染层都要改一遍?!</em></p><p>所以现有业务系统切换到无栈协程的成本非常高。</p><p>就个人经历来说,我写过amphp、写过JS/TS、很早之前也试过Python3的asyncio。</p><p>体验就是,作为开发者,需要严格注意返回的是generator还是一个普通的对象/value。</p><p>要是写错,那么线上就炸了…… 而且IDE的智能提示,在这儿也无能为力。</p><p>所以,一个技术,如果只能大师才能用得起来,那么它就无法大规模流行。无栈协程就处于这样尴尬的场景。</p><p><strong>1.2有栈协程</strong></p><p>代表有gevent的monky patch,golang,Java的loom,还有</p><p><a href="//www.zhihu.com/people/9cbce625abc37bc0125ce39efbd61867">@韩天峰</a></p><p>大佬的swoole(协程部分)和这次的Fiber,他们本质上都是有栈协程。</p><p>有栈协程的特点就是,协程的切换是Runtime控制的,不用手动一层一层yield。</p><p>比如一个函数,发起IO调用,那么Runtime就能把这个协程挂起,然后调度到别的协程,IO完成后,这个协程继续执行。</p><p>整个过程中,协程都“感知不到”发生了切换。</p><p>这时候,开发人员才能安全的使用协程。</p><p>底层切换到协程,上层不用做任何改造。</p><p>还是上面的例子,DB driver切换到协程版本,基本上业务代码不用动。</p><p>基本上Golang的并发模型就是这样子的,就像</p><p><a href="//www.zhihu.com/people/b0b8a09df75429a529b0c75510176e87">@涛叔</a></p><p>之前说的“Golang就是高级的PHP”。</p><p><strong>2 Fiber和Swoole</strong></p><p>好,聊完了协程,我们再看下Fiber和Swoole:</p><p>个人认为,Fiber作为有栈协程的尝试,是PHP协程标准化的一个进步。虽然IO事件部分还是缺失的,但方向是对的,IO事件部分后面会逐步补上。</p><p>Swoole是一个非常好的先驱者,但Swoole在推进协程标准化上做得不多。标准化阵地就在这儿,Swoole不占领,Fiber就会来占领。</p><p>从生态角度、后续PHP协程的发展前景来看,还是<strong>希望</strong></p><p><strong><a href="//www.zhihu.com/people/9cbce625abc37bc0125ce39efbd61867">@韩天峰</a></strong></p><p><strong>大佬以及Swoole团队能够推进标准化</strong>。</p><p>Fiber现阶段对于Amp以外的项目价值很少,但是随着周边生态,比如IO事件系统、协程调度系统、协程同步语义逐步建立起来后,PHP开发者还是会逐步使用的,长远来看,还是<strong>需要注意这个提案的影响</strong>。</p><p>所以建议<strong>Swoole团队能够及时把自己的修改合并到上游,争取到更大的PHP内核发言权</strong>。</p><p><strong>3 番外</strong></p><p><strong>3.1 CPU密集型</strong></p><p>我们说了这么久的协程,但是协程要解决的是IO密集型的问题。那么CPU密集型的呢?目前看起来主要靠多进程来实现(至少对于众多脚本语言来说是这样)。</p><p>在这一块上,<strong>PHP还缺少一个多进程的管理器</strong>,目前<a href="https://link.zhihu.com/?target=https%3A//www.php.net/manual/en/book.parallel.php">PHP的parallel</a>做了一些尝试,但是目前看起来不是很好用。</p><p><strong>3.2 by-pass内核</strong></p><p>让我们目前再放长远一点,现在计算机结构中,越来越多的by-pass kernel的方式出现:</p><p>内核处理不好线程调度,那么搞协程,用户自己来调度。(无栈协程改造成本太大,所以都采用有栈协程)</p><p>内核处理不好网络包,那么搞DPDK,用户自己来处理网络包。(用户自己要独占网卡,很容易出问题;所以需要一个好的共享网卡的by-pass网络栈,现在DPDK的KNI是一个不错的尝试,但是显然不够)</p><p>在by-pass kernel这一块,还有没有更加好玩的东西呢?这是一个值得思考的问题。</p><p>话说到这儿了,那就再多说两句。</p><p><strong>3.3 计算机技术的价值</strong></p><p>本科时候,计算机导论是<a href="https://link.zhihu.com/?target=https%3A//www.dhu.edu.cn/2015/0309/c5961a59333/page.htm">乐嘉锦院长</a>教的,他说过一句话,大意如下:</p><blockquote><p>现在我们写程序,都是计算机结构都已经定好了,然后我们再往里面填代码。真正应该做的是:根据需求设计计算机,而不是被计算机结构框住。</p></blockquote><p>当时觉得,这句话大而无当,没啥意思。现在想来,这句话契合了最近几年计算机的发展途径:</p><p>从上面内核不能满足需求,我们by-pass内核;再到CPU不能满足需求,我们开始设计AI芯片。</p><p>这后面的逻辑是啥呢?我觉得可以汇总成一句话:</p><p><strong>计算机技术和其他技术一样,都要满足客户需求,把价值交付给客户。</strong></p><p><a href="//www.zhihu.com/question/448805077/answer/1778652091">发布于 03-14</a></p><hr/><p>作者:匿名用户<br/>链接:<a href="https://www.zhihu.com/question/448805077/answer/1778546652%5C">https://www.zhihu.com/question/448805077/answer/1778546652\</a> 来源:知乎<br/>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p><p>跑题说一些我知道的。</p><ol><li>swoole 团队曾经发邮件想表达希望合并到内核。得到的回复当然是你得写提案和有充足的单元测试,必须是 c 语言,并且只希望提供协程 API 部分。swoole 团队的人似乎认定内核组太保守,之后就不了了之了。其实内核组没错,php 社区是很公平的社区,提案起草要经过内部讨论和投票才能合并到内核。合并特性内容可控,通过率才会高。</li><li>swoole 团队基于积累经验开发了 swow,算是 swoole 的简化版,只实现了协程相关,事件驱动用了外部的。大概是去年(2020) 开始的项目,说是会努力合并到内核。作者 twosee 也努力开发,一边也参与内核的贡献积累影响力。</li><li>fiber 是去年九月左右开始起草的提案,12 月正式内部讨论,当时 swoole 相关的群有人分享了这一消息。然而,swoole 社区并没有太在意,觉得自己的 swoole 才是最强的。这个月月初 fiber 正式开始投票,开局就是11-2,投反对票的两人均来自 swoole 社区。</li><li>最引起社区注意的是,投票阶段 swoole 社区的同学突然邮件内部全员说不支持 fiber,理由主要是两个: fiber 进入内核最大的收益者是 amphp 社区;fiber 太简单,完整的协程支持需要考虑各种各样。</li><li>swow 作者看到 fiber 这么随便就提案合并,说今年也会尝试提案,不管 fiber 是否通过。</li></ol><p><a href="//www.zhihu.com/question/448805077/answer/1778546652">编辑于 03-13</a></p><hr/><p>viproot 程序员</p><p>希望swoole的作者能多考虑php的未来,而不是swoole的未来,swoole虽然扩展了php的能力,但是换句话说swoole对php语言发展并没有做出太大贡献</p><p><a href="https://www.zhihu.com/question/448805077/answer/1787165977">发布于 03-18</a></p><hr/><p>作者:涛叔<br/>链接:<a href="https://www.zhihu.com/question/448805077/answer/1777527343%5C">https://www.zhihu.com/question/448805077/answer/1777527343\</a> 来源:知乎<br/>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p><p>我实名反对</p><p><a href="//www.zhihu.com/people/9cbce625abc37bc0125ce39efbd61867">@韩天峰</a></p><p>的回答。PHP开发者社区好久没有这样的瓜了。容我为大家细细道来。</p><p>我也是 PHP 出身,给 Swoole 贡献过代码。我甚至在2017年的时候也想给 PHP 添加 Fiber 性,参见<a href="https://link.zhihu.com/?target=https%3A//wiki.php.net/rfc/fiber">这里</a>。限于技术水平,我的方案有缺陷,没有得到认可。后来就不了了之了。再后来,我转用Go语言,不怎么关注PHP。</p><p>直到昨天我才知道又有开发者尝试给PHP添加 Fiber 特性了。我惊喜万分。于是看了一下它的<a href="https://link.zhihu.com/?target=https%3A//wiki.php.net/rfc/fibers">RFC</a>。他们甚至还在RFC中提到了我之前写的RFC,我之前写的RFC</p><blockquote><p>The prior <a href="https://link.zhihu.com/?target=https%3A//wiki.php.net/rfc/fiber">Fiber RFC</a> did not support context switching within internal calls (<code>array_map</code>, <code>preg_replace_callback</code>, etc.) or opcode handlers (<code>foreach</code>, <code>yield from</code>, etc.). This could result in a crash if a function using fibers was used in any user code called from C code or in extensions that override <code>zend_execute_ex</code> such as Xdebug.</p></blockquote><p>写的也很中肯。当时我只想处理纯PHP代码Fiber,不想管复杂的C函数栈问题。被拒绝也是预料之中的事。</p><p>好了,背景就这么多。我们说正题。</p><p>在吃瓜之前,我们得先看看瓜长什么样。不然大家会限入文化和意识形态之争。</p><p>第一个要澄清的是并行跟并发的概念。并行可以理解成同时执行,这个需要硬件支持。你如果你的CPU只有一核,那程序不可能并行。并发可以理解成共同执行,主要是一个软件概念。我们就是在单核CPU上也能同时写文档、听音乐。为什么,因为操作系统一般都支持按时间片调度,不同的程序可以交替执行一段时间(时间片)。因为切换的速度特别快,大家感觉不出来罢了。当然了,如果你的CPU有多核,那就可以并行执行,不用交替切换了。但CPU的核数是有限的,你想运行的程序却很多,所以现在的计算机都是同执行并行和并发操作。而并行就是并发的一种实现方式。</p><p>总之,并行跟迸发是操作系统的基本概念,学过的同学应该都清楚。我们今天说的<strong>Fiber是为了解决并发问题</strong>,而不是并行问题。大家在吃瓜之前务必要记住这一点。</p><p>回到Fiber。Fiber也叫纤程,其实跟协程是一个概念。</p><p>我们讲并发编程无非就是进程、线程、协程。无论是进程还是线程,都可以并发执行,都有自己的栈空间。所以不同线程调用同一函数基本是不会相互影响的(没有使用全局量)。同时,进程跟线程的调度是同操作系统完成的,调度消耗资源比较多、比较慢;而因为有独立的栈空间和其他相关信息,进程和线程也会占用很多系统资源。所以说,我们没法在系统里创建很多进程和线程。即便我们有足够多的内存,我们强行启动成千上万个进程和线程,操作系统在调度的时候也会非常吃力。</p><p>为了解决这个问题,人们决定不让操作系统调度,自己上。于是就有了「用户态」线程这样的概念,这就是所谓的协程。从某种成度上看,协程就是一种线程,一种需要<strong>用户自行调度</strong>的线程。因为不需要操作系统的介入,调度的效率会比较高,资源的消耗比较小。所以现在有些人一提起高并发编程就要用协程。</p><p>这里的用户自行调度是相对于操作系统来说的。这个用户可以是程序员,也可以是编译器或运行时。不同的语言处理手法也各不相同。像是Go语言,就是在运行时完成协程调度的。协程在执行的时候如果遇到阻塞(比如网络数据没收到等)就会自动暂停执行,等相关资源就绪之后运行时会按某种规则唤醒。像PHP的generator就需要yield来暂停,再通过resume来恢复。</p><p>PHP本身是多进程模式(不完全对)。从5.4开始,PHP支持所谓的generator。我个人认为PHP的generator最开始是为了解决大批量数据处理时的内存占用问题。看如下代码:</p><div class="relative"><pre><code class="language-php code-highlight"><span class="code-line"><span class="token language-php php"><span class="token delimiter important">&lt;?php</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token keyword">function</span> <span class="token function function-definition">xrange</span><span class="token punctuation">(</span><span class="token variable">$start</span><span class="token punctuation">,</span> <span class="token variable">$end</span><span class="token punctuation">,</span> <span class="token variable">$step</span> <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token variable">$i</span> <span class="token operator">=</span> <span class="token variable">$start</span><span class="token punctuation">;</span> <span class="token variable">$i</span> <span class="token operator">&lt;=</span> <span class="token variable">$end</span><span class="token punctuation">;</span> <span class="token variable">$i</span> <span class="token operator">+=</span> <span class="token variable">$step</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token keyword">yield</span> <span class="token variable">$i</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token punctuation">}</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token punctuation">}</span> </span></span><span class="code-line"><span class="token language-php php"> </span></span><span class="code-line"><span class="token language-php php"><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token function">xrange</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1000000</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token variable">$num</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token keyword">echo</span> <span class="token variable">$num</span><span class="token punctuation">,</span> <span class="token string double-quoted-string">&quot;\n&quot;</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token punctuation">}</span> </span></span><span class="code-line"><span class="token language-php php"> </span></span></code></pre></div><p>在 foreach 中,调用 xrange 会返回一个 generator 对象,而非直接分配一个有一百万元素的数组。foreach 在每次循环的时候都会调用 generator 对像的 send 方法来获取下一个元素。而这个 generator 会执行 xrange 方法,一直走到 yield。这个 yield 可以理解为临时的 return。xrange执行到 yield 会暂停,send 方法就会返回 yield 后面的 $i。当 foreach 再次调用 send 的时候,generator 会从上一次 yield 的地方继续向下执行。</p><p>所以说,generator 对象一不小心给 PHP 添加了<strong>暂停函数</strong>的特技。基于此,人们想给PHP添加协程功能。最基础的思路在<a href="https://link.zhihu.com/?target=https%3A//www.npopov.com/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html">这里</a>,作者是nikic,本身就是 generator 的开发者。从那以后,PHP社区出现了好多基于 generator 的协程框架。最著名的要属<a href="https://link.zhihu.com/?target=https%3A//amphp.org/">https://amphp.org</a>,而amphp社区正是本次php-fibers RFC的推动者。</p><p>有了 generator 为什么还要引入 fiber 呢?那是因为当前的 generator 不支持暂停子函数调用。</p><p>一般来说我们的代码都是分层的,比如是 api -&gt; controller -&gt; service -&gt; model -&gt; util。可能从 api 调 controller 一直调到 model 都没有阻塞操作,但 model 调 util 可能需要访问 db 连接,数据可能没有传回,在这种情况下,我们希望<strong>暂停从 api 到 util 的整个调用栈</strong>,等数据传回的时候再继续执行。很可惜,generator 不支持这样的操作。</p><p>如果要实现<strong>暂停从 api 到 util 的整个调用栈</strong>,我们就必需在调用 api 函数之前准备好一个独立的函数调用栈,用这个独立的栈保存各层函数调用的各种数据。这显然是非常复杂的。像 nodejs 等好多语言直接决定不支持这种暂停效果,不会为协程分配独立栈空间。这种叫 stackless coroutine。php了 generator 也采用这种策略。</p><p>这种策略的好处就是实现简单,性能高,对应的功能也简单。而且不能实现<strong>暂停从 api 到 util 的整个调用栈</strong>的效果。如果你要用,必须重写现有的代码。如果你用nodejs,你不得不处理各种async/await逻辑。用async/await写过业务逻辑的人肯定不会愉快。关于这个问题,有人专门写了这篇文章<a href="https://link.zhihu.com/?target=https%3A//journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/">What Color is Your Function?</a></p><p>而我们要说的 fiber 就是为了解决 generator 不能<strong>暂停从 api 到 util 的整个调用栈</strong>这个问题的。</p><p>这个问题其实非常复杂。PHP本身有Zend虚拟机,Zend虚拟机有自己的栈。PHP还有好多功能是通过扩展实现的,而扩展都是用C开发的,所以会用到C运行时的栈。如果要实现Fiber,必须同时分配 C和Zend的栈,确实有难度。但amphp社区的开发者做到了。而且得到了PHP的认可。</p><p>我给大家举个使用 fiber 的例子,好让大家有个直观的感受</p><div class="relative"><pre><code class="language-php code-highlight"><span class="code-line"><span class="token language-php php"><span class="token delimiter important">&lt;?php</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token keyword">function</span> <span class="token function function-definition">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">int</span> <span class="token punctuation">{</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token keyword">echo</span> <span class="token scope">Fiber<span class="token punctuation">::</span></span><span class="token function">suspend</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token keyword">echo</span> <span class="token scope">Fiber<span class="token punctuation">::</span></span><span class="token function">suspend</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token keyword">echo</span> <span class="token scope">Fiber<span class="token punctuation">::</span></span><span class="token function">suspend</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token punctuation">}</span> </span></span><span class="code-line"><span class="token language-php php"> </span></span><span class="code-line"><span class="token language-php php"><span class="token variable">$fiber</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Fiber</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token function">hi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"> <span class="token keyword">echo</span> <span class="token scope">Fiber<span class="token punctuation">::</span></span><span class="token function">suspend</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"> </span></span><span class="code-line"><span class="token language-php php"><span class="token keyword">echo</span> <span class="token variable">$fiber</span><span class="token operator">-&gt;</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token keyword">echo</span> <span class="token variable">$fiber</span><span class="token operator">-&gt;</span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token string single-quoted-string">&#x27;a&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token keyword">echo</span> <span class="token variable">$fiber</span><span class="token operator">-&gt;</span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token string single-quoted-string">&#x27;b&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token keyword">echo</span> <span class="token variable">$fiber</span><span class="token operator">-&gt;</span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token string single-quoted-string">&#x27;c&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"><span class="token keyword">echo</span> <span class="token variable">$fiber</span><span class="token operator">-&gt;</span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token string single-quoted-string">&#x27;d&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span></span><span class="code-line"><span class="token language-php php"> </span></span></code></pre></div><p>我们定义了一个Fiber,并在fiber中调用了hi函数。</p><p>当我们调用 start 函数的时候,fiber 开始执行,一直执行到 hi 函数的第一个 Fiber::suspend。这个 suspend 跟前面的 yield 是类拟的,他会把参数1返给 start 函数。从直观上看,我们调了 start 函数,得到了一个返回值1。跟普通的函数调用没什么两样。但请大家注意hi函数的第一行,调用suspend函数不会返回也就是说echo也不会执行。从直观上看,这一行是调了suspend函数,期待返回一个值并奖其输出。</p><p>前面的start()返回后echo会输出suspend返回的数字1整个fiber就进入了暂停状态。此时程序输出1.</p><p>如果我们调一下resume函数,传入参数&#x27;a&#x27;。fiber 就会恢复执行,而且是从上一次suspend的地方继续执行。从效果上看仿佛是之前的suspend函数调用结束了,并返回了一个&#x27;a&#x27;。这个时候hi第一行的echo就会输出&#x27;a&#x27;,然后继续执行到第二个supend。</p><p>总而言之,就是实现了之前所说的<strong>暂停从 api 到 util 的整个调用栈</strong>这个效果**。**</p><p>等等,这个事情跟</p><p><a href="//www.zhihu.com/people/9cbce625abc37bc0125ce39efbd61867">@韩天峰</a></p><p>有什么关系呀?为什么他要跳出来反对呢?</p><p>Fiber 本质上赋予了 PHP 在用户态临时暂停任意函数调用的特技。如果配合外部事件调度框架(可以完全用PHP实现),就可以实现 swoole 的大多数功能。而且,更关键的点在于,PHP社区现有庞在的类库几乎只做很少的改动就能适配到 fiber 上进而获得并发执行的能力。这跟swoole需要内置各种协程版类库形成了鲜明的对比。最后,因为 fiber 会合并到 php 内核,由官方背书。一旦投票通过,会得到整个社区的支持。届时,swoole 就会被逐步边缘化。</p><p>所以,swoole 相关的人就开始反对了。关于反对的内容,建议大家直接看原始讨论邮件,不要相信一家之言</p><ol><li><a href="https://link.zhihu.com/?target=https%3A//externals.io/message/113430">https://externals.io/message/113430</a></li><li><a href="https://link.zhihu.com/?target=https%3A//externals.io/message/113419">https://externals.io/message/11341</a></li><li><a href="https://link.zhihu.com/?target=https%3A//externals.io/message/112538">https://externals.io/message/112538</a></li></ol><p>就我观察,swoole是很难合并到 php 内核的。因为swoole太重了,更多是个框架,而不是语言特性。可以说swoole从一开始就没有想好怎么做才能合到php内核。swoole开源快十年了。一直不去解决如何合并到内核的问题。现在有人提供了相关方案,自己就坐不住了。</p><p>Fiber作为一个简单的特性,反而为大家提供了无限的想像空间。fiber框架提出一开始,大家基本都在讨论如何改进这个提案,如何让他快速合并到内核。唯有swoole相关的人,采用了完全对立的态度,基本上是为了反对而反对。</p><p>fiber本身跟swoole没有竞争关系。说到底fiber只是一个增强型的generator。但是,基于fiber,我们可以用纯php打造一套跟swoole竞争的框架,而且现有的php类库也可以很容易地完成适配,这可能是 swoole 社区最害怕的。</p><p>从目前投票来看,fiber 特性可能要被通过了。到时候看 swoole 社区如何应对吧。</p><p><a href="//www.zhihu.com/question/448805077/answer/1777527343">编辑于 03-13</a></p><hr/><p>作者:匿名用户<br/>链接:<a href="https://www.zhihu.com/question/448805077/answer/1777447935%5C">https://www.zhihu.com/question/448805077/answer/1777447935\</a> 来源:知乎<br/>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p><p>大家都是写异步协程框架,Swoole一言不合就AMP不行,ReactPHP不行。那你行你倒是提个提案?难怪国内无论知乎还是论坛Swoole人见人骂,Diss同行,恶心同行的方式真是一绝。</p><p>现在开始说为了PHP的发展了,你Swoole搞了那么多年,你咋不想着促进PHP协程的发展呢?你咋不想着提个提案?现在有人抛出来fiber,觉得影响你在国内的一亩三分地了,开始跳起来了?开始装圣人了?</p><p>目测fiber最终会通过。</p><p>-----------------------------------------------分割线-----------------------------------------</p><p>完整的邮件请查看</p><p><a href="https://link.zhihu.com/?target=https%3A//externals.io/message/113430">https://externals.io/message/113430​externals.io</a></p><p>与</p><p><a href="https://link.zhihu.com/?target=https%3A//externals.io/message/113419">https://externals.io/message/113419​externals.io</a></p><p>此外,不得不说一下,在邮件里,<strong>Dan Ackroyd</strong>询问</p><p>Please could you disclose the commercial interests of the Swoole<br/>maintainers, and the ties to the for profit companies that provide<br/>services implementing Swoole?</p><p>Having people vote on RFCs who have ties to companies that provide<br/>services via commercial entities isn&#x27;t unprecedented. For example<br/><a href="https://link.zhihu.com/?target=http%3A//zend.com/">zend.com</a> has had employees who are involved in voting on RFCs, but to<br/>a large extent that was done openly, with all of them using <a href="https://link.zhihu.com/?target=http%3A//zend.com/">zend.com</a><br/>email addresses.</p><p>而<strong>rango</strong>回答声称:</p><p>We have no commercial purpose on the swoole open source project. This is a purely technical project.</p><p><a href="//www.zhihu.com/question/448805077/answer/1777447935">编辑于 03-14</a></p><p>《<a href="https://www.zhihu.com/question/448978565">如何看待Swoole作者声称Swoole没有商业目的,反对Fiber提案毫无私心?</a>》</p><p>作者:匿名用户<br/>链接:<a href="https://www.zhihu.com/question/448805077/answer/1777447935%5C">https://www.zhihu.com/question/448805077/answer/1777447935\</a> 来源:知乎<br/>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p><p>大家都是写异步协程框架,Swoole一言不合就AMP不行,ReactPHP不行。那你行你倒是提个提案?难怪国内无论知乎还是论坛Swoole人见人骂,Diss同行,恶心同行的方式真是一绝。</p><p>现在开始说为了PHP的发展了,你Swoole搞了那么多年,你咋不想着促进PHP协程的发展呢?你咋不想着提个提案?现在有人抛出来fiber,觉得影响你在国内的一亩三分地了,开始跳起来了?开始装圣人了?</p><p>目测fiber最终会通过。</p><p>-----------------------------------------------分割线-----------------------------------------</p><p>完整的邮件请查看</p><p><a href="https://link.zhihu.com/?target=https%3A//externals.io/message/113430">https://externals.io/message/113430​externals.io</a></p><p>与</p><p><a href="https://link.zhihu.com/?target=https%3A//externals.io/message/113419">https://externals.io/message/113419​externals.io</a></p><p>此外,不得不说一下,在邮件里,<strong>Dan Ackroyd</strong>询问</p><p>Please could you disclose the commercial interests of the Swoole<br/>maintainers, and the ties to the for profit companies that provide<br/>services implementing Swoole?</p><p>Having people vote on RFCs who have ties to companies that provide<br/>services via commercial entities isn&#x27;t unprecedented. For example<br/><a href="https://link.zhihu.com/?target=http%3A//zend.com/">zend.com</a> has had employees who are involved in voting on RFCs, but to<br/>a large extent that was done openly, with all of them using <a href="https://link.zhihu.com/?target=http%3A//zend.com/">zend.com</a><br/>email addresses.</p><p>而<strong>rango</strong>回答声称:</p><p>We have no commercial purpose on the swoole open source project. This is a purely technical project.</p><p><a href="//www.zhihu.com/question/448805077/answer/1777447935">编辑于 03-14</a></p><hr/><p>作者:吃的<br/>链接:<a href="https://www.zhihu.com/question/448978565/answer/1779597343%5C">https://www.zhihu.com/question/448978565/answer/1779597343\</a> 来源:知乎<br/>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p><p>有无私心只有他本人才知道,我们不恶意揣测,但swoole的总总做法,圈内早以是有所耳闻的。关于此次fiber提案,swoole作者的看法大致是</p><p>1、因为协程化困难、工作量大,希望把fiber推迟到php9。这显然不是社区要的,目前php处在这尴尬的局面,正是需要强有力技术栈来推动发展,一个协程最小化核心的实现你建议推迟到php9,再过个几年?等社区把一切都安排好了,大部分人都不用php了再上吗?这是何居心啊。</p><p>2、因为fiber只是协程最小化核心,普通开发用不上,大家要的是开箱即用、完整式的协程栈。话是没错,但协程需要的几个技术点目前php社区都有,基于进程的io 多路复用、event loop 、协程调度、非阻塞网络库,那一个没有?只是高效率低效率,最佳实践的问题罢了。至少amphp、reactphp 、symfony process都很明确需要这种最小化核心的,别忽悠大伙儿。</p><p>3、python、ruby等动态语言在加入fiber后并没有在并发编程上取得多大成绩。这个就仁者见仁 智者见智了,但我们想说的是,“有总比没有好,我可以不用但php不能没有”,这是大家的心声,以后的事谁能预料呢?</p><p>总的来说,在协程化生态上目前swoole是走在最前面的,作为一名普通开发,希望swoole能提供你们的宝贵经验,让php能走点更远一点,而不是在这内耗。</p><p><a href="//www.zhihu.com/question/448978565/answer/1779597343">发布于 03-14</a></p><hr/><p>我觉得加入好啊.</p><p>最小的,其它的实现可以慢慢来</p><p>swoole那套太复杂了,为了实现携程加入了太多的新东西</p><p>不如直接go<br/>简单的东西也不如workerman之类的解决办法</p><p><a href="https://www.zhihu.com/question/448978565/answer/1780961967">发布于 03-15</a></p> Sun, 21 Mar 2021 14:43:52 GMT ttyS3 phpfiberasync https://ttys3.dev/blog/how-to-copy-message-command-output-to-system-clipboard-in-vim vim 如何复制 message 命令的输出到系统剪切板 https://ttys3.dev/blog/how-to-copy-message-command-output-to-system-clipboard-in-vim <blockquote><p>vim 要支持复制到系统剪切板,首先要确保系统安装了 xclip 之类的剪切板工具。</p></blockquote><p>主要的使用场景是复制一些错误信息。</p><p>要复制 <code>:message</code> 的输出, 解决办法就是将输出重定向剪切板。</p><p>the clipboard register (<code>@+</code>) or primary register (<code>@*</code>)</p><p>比如:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">:redir @+ </span><span class="code-line">:3message </span><span class="code-line">:redir END </span></code></pre></div><p>See <code>:help :redir</code>, <code>:help :message</code></p><p>当然,每次都敲这么多命令也是挺麻烦的,直接定义一个名为 <code>CpMsg</code> command 好了:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">command<span class="token operator">!</span> <span class="token parameter variable">-bang</span> CpMsg redir @+ <span class="token operator">|</span> 99message <span class="token operator">|</span> redir END </span></code></pre></div><p>refs</p><p><a href="https://stackoverflow.com/questions/41663646/how-to-copy-to-clipboard-3-last-lines-from-messages/41664344#41664344">https://stackoverflow.com/questions/41663646/how-to-copy-to-clipboard-3-last-lines-from-messages/41664344#41664344</a></p><p><a href="https://superuser.com/questions/167352/how-do-i-copy-command-output-in-vim/171105#171105">https://superuser.com/questions/167352/how-do-i-copy-command-output-in-vim/171105#171105</a></p> Sun, 21 Mar 2021 14:16:08 GMT ttyS3 https://ttys3.dev/blog/sysctld-not-applied sysctl.d 未生效问题 https://ttys3.dev/blog/sysctld-not-applied <p>新装的 Arch , 发现 <code>/etc/sysctl.d/01-sysrq.conf</code> 里设置的 <code>kernel.sysrq = 1</code> 没有生效。</p><p>检测 <code>/proc/sys/kernel/sysrq</code> 的值发现是 <code>16</code></p><p>先检查下 systemd 相关服务是否正常运行了, 结果是完全正常:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ systemctl status systemd-sysctl.service </span><span class="code-line">● systemd-sysctl.service - Apply Kernel Variables </span><span class="code-line"> Loaded: loaded <span class="token punctuation">(</span>/usr/lib/systemd/system/systemd-sysctl.service<span class="token punctuation">;</span> static<span class="token punctuation">)</span> </span><span class="code-line"> Active: active <span class="token punctuation">(</span>exited<span class="token punctuation">)</span> since Sun <span class="token number">2021</span>-03-21 <span class="token number">20</span>:12:34 CST<span class="token punctuation">;</span> 1h 45min ago </span><span class="code-line"> Docs: man:systemd-sysctl.service<span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">)</span> </span><span class="code-line"> man:sysctl.d<span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span> </span><span class="code-line"> Process: <span class="token number">324</span> <span class="token assign-left variable">ExecStart</span><span class="token operator">=</span>/usr/lib/systemd/systemd-sysctl <span class="token punctuation">(</span>code<span class="token operator">=</span>exited, <span class="token assign-left variable">status</span><span class="token operator">=</span><span class="token number">0</span>/SUCCESS<span class="token punctuation">)</span> </span><span class="code-line"> Main PID: <span class="token number">324</span> <span class="token punctuation">(</span>code<span class="token operator">=</span>exited, <span class="token assign-left variable">status</span><span class="token operator">=</span><span class="token number">0</span>/SUCCESS<span class="token punctuation">)</span> </span></code></pre></div><p>测试<code>sudo SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-sysctl</code> 发现,<code>sysrq</code> 被 默认的规则</p><p><code>/usr/lib/sysctl.d/50-default.conf</code> 覆盖掉了。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ rg sysrq /usr/lib/sysctl.d/50-default.conf </span><span class="code-line"><span class="token number">16</span>:<span class="token comment"># Use kernel.sysrq = 1 to allow all keys.</span> </span><span class="code-line"><span class="token number">17</span>:<span class="token comment"># See https://www.kernel.org/doc/html/latest/admin-guide/sysrq.html for a list</span> </span><span class="code-line"><span class="token number">19</span>:kernel.sysrq <span class="token operator">=</span> <span class="token number">16</span> </span></code></pre></div><p>由于我们的文件名是 <code>01-sysrq.conf</code> , 在50之前执行,因此,我们需要系统默认配置执行完再覆盖,把文件名改成 <code>99-sysrq.conf</code> 即可:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ bat /etc/sysctl.d/99-sysrq.conf </span><span class="code-line"><span class="token comment"># been set in 50-default.conf</span> </span><span class="code-line"><span class="token comment"># so we need override it later</span> </span><span class="code-line">kernel.sysrq <span class="token operator">=</span> <span class="token number">1</span> </span></code></pre></div><p>refs</p><p><a href="https://wiki.archlinux.org/index.php/sysctl#Configuration">https://wiki.archlinux.org/index.php/sysctl#Configuration</a></p><p><a href="https://wiki.archlinux.org/index.php/Keyboard_shortcuts#Kernel_(SysRq)">https://wiki.archlinux.org/index.php/Keyboard_shortcuts#Kernel_(SysRq)</a></p> Sun, 21 Mar 2021 13:50:21 GMT ttyS3 sysctl.dsysctlarchlinux https://ttys3.dev/blog/linux-lark-gtk Linux Lark GTK https://ttys3.dev/blog/linux-lark-gtk <p>飞书原名叫 Lark.</p><p>有Mac, Windows 和 Web 版。</p><p>不过打开很多 Tab 的浏览器里找 飞书 的 Tab, 确实不太方便。于 Github 找到一个 用 Electron 包了一下 飞书 Web 的客户端。</p><p>使用 electron builder 构建 AppImage / ArchLinux .pkg.tar.xz / rpm / deb 包等还是非常方便, electron builder 实际上采用的是一个基于 ruby 的打包工具,叫 fpm</p><p>不得不说Electron的工具还是蛮完善的。</p><div><img alt="" src="https://ttys3.dev/static/assets/electron-builder-KN7BKC7W.png" width="1630" height="533"/></div><p>有两个小问题:</p><ol><li>隐藏到托盘后没法显示了。</li><li>点击消息里的链接,是用的 Electron 打开的,而不是调用的系统默认浏览器。</li></ol><p>但是,老灯使用一段时间后发现了 node.js Electron 版的飞书最大的一个问题是,连续跑几天,会导致 GNOME 桌面的所有窗体的标题文字不见了。 由于短时间无法重现,导致问题也很难排查。</p><p>最张,老灯没办法,自动操刀用学了几天的 Rust 写了一个 GTK 版的 lark-gtk</p><p>老灯已经上传新的 release 在这 <a href="https://github.com/ttys3/lark-for-linux/releases/tag/v0.5.1">https://github.com/ttys3/lark-for-linux/releases/tag/v0.5.1</a></p><p>refs</p><p><a href="https://www.electron.build/configuration/linux">https://www.electron.build/configuration/linux</a></p><p><a href="https://github.com/jordansissel/fpm/wiki#usage">https://github.com/jordansissel/fpm/wiki#usage</a></p><p><a href="https://gtk-rs.org/">https://gtk-rs.org/</a></p> Thu, 11 Mar 2021 17:16:18 GMT ttyS3 larkgtkrust https://ttys3.dev/blog/myrocks-rocksdb-based-storage-engine-for-mysql MyRocks -- RocksDB based storage engine for MySQL https://ttys3.dev/blog/myrocks-rocksdb-based-storage-engine-for-mysql <p>底层存储引擎基于 LevelDB 或 RocksDB 的 Key-Value DB 挺多的,比如 <a href="https://github.com/ideawu/ssdb">SSDB</a> , 360开源的 <a href="https://github.com/Qihoo360/pika">Pika</a> 以及腾讯开源的 <a href="https://github.com/Tencent/Tendis">Tendis</a></p><p>但是基于 RocksDB 的 关系型数据库,老灯最近才了解到, 原来 FaceBook 搞的 MySQL MyRocks 引擎已经存在好多年了。简单地浏览了一下文档,InnoDB 算是在写入和读取方面都比较好,而 MyRocks 引擎 主要是写入性能强劲,对于读取来说相对弱一些。 先 mark 一下吧。</p><p><a href="https://zhuanlan.zhihu.com/p/45652076">MyRocks及其使用场景分析</a> 温正湖</p><p><a href="https://www.percona.com/blog/2020/08/04/the-road-story-of-a-myrocks-mariadb-migration/">The Road Story of a MyRocks/MariaDB Migration</a></p><p><a href="http://myrocks.io/">http://myrocks.io/</a></p><p><a href="https://www.percona.com/blog/2018/02/01/myrocks-engine-things-know-start/">MyRocks Engine: Things to Know Before You Start</a></p><p><a href="https://engineering.fb.com/2016/08/31/core-data/myrocks-a-space-and-write-optimized-mysql-database/">MyRocks: A space- and write-optimized MySQL database</a></p> Sun, 07 Mar 2021 16:40:50 GMT ttyS3 mysqlmariadbrocksdbmyrocks https://ttys3.dev/blog/mariadb-binlog-compress MariaDB binlog压缩 https://ttys3.dev/blog/mariadb-binlog-compress <p>先 mark 记录一下。</p><blockquote><p>log_bin_compress——这个配置决定了是否可以压缩二进制日志。这个增强功能是 MariaDB 独有的,因此 MySQL 不支持。</p></blockquote><p><a href="https://www.infoq.cn/article/mariadb-vs-mysql">https://www.infoq.cn/article/mariadb-vs-mysql</a></p><p>binlog压缩 为了减小binlog的存储开销。在TenDB中,基于ZLIB算法实现了binlog压缩的功能。该功能可以在运行中开启和关闭,并且适用于statement,row,mixed格式。</p><p>压缩 开启Binlog压缩:</p><p>```shell</p><p>set global log_bin_compress=ON ```</p><p>Binlog压缩阈值:</p><p>```shell</p><p>set global log_bin_compress_min_len=256 ```</p><p>在开启压缩功能的前提下,binlog字段长度大于256的event,符合压缩条件。</p><p>经过测试,在通常情况下,启用binlog压缩功能,可以达到7-9的压缩比。是以CPU为代价缓解了IO压力的良好实践。</p><p>解压 有两种解压的方式可以选择:</p><p>让binlog在IO线程中解压:</p><p>```shell</p><p>set global relay_log_uncompress = ON ```</p><p>让binlog在sql线程中解压:</p><p>```shell</p><p>set global relay_log_uncompress = OFF ```</p><p>如果slave机器,relay-log空间够,可以set global relay_log_uncompress=ON(默认配置),在binlog在IO线程中解压。 如果slave机器,relay-log空间不够,可以set global relay_log_uncompress=OFF,让binlog在sql线程中解压,但是这样可能会导致sql线程变慢。 但slave都有并行同步能力,所以在sql线程解压一般不会对运行速度有很大影响。</p><p>兼容性</p><p>新增了4种事件类型: QUERY_COMPRESSED_EVENT表示statement格式下压缩后的DML事件; WRITE_ROWS_COMPRESSED_EVENT,UPDATE_ROWS_COMPRESSED_EVENT和DELETE_ROWS_COMPRESSED_EVENT分别表示row格式下插入,更新和删除在压缩后的事件。</p><p>推荐使用TenDB的mysqlbinlog工具进行binlog操作。</p><p><a href="https://tendbcluster.com/book-cn/Documentation/tendb/binlog-compress.html">https://tendbcluster.com/book-cn/Documentation/tendb/binlog-compress.html</a></p><p>log_bin_compress <a href="https://mariadb.com/kb/en/replication-and-binary-log-system-variables/#log_bin_compress">https://mariadb.com/kb/en/replication-and-binary-log-system-variables/#log_bin_compress</a></p><p>log_bin_compress_min_len <a href="https://mariadb.com/kb/en/replication-and-binary-log-system-variables/#log_bin_compress_min_len">https://mariadb.com/kb/en/replication-and-binary-log-system-variables/#log_bin_compress_min_len</a></p><p><a href="https://mysql.wisborg.dk/2020/05/07/mysql-compressed-binary-logs/">https://mysql.wisborg.dk/2020/05/07/mysql-compressed-binary-logs/</a></p><p><a href="https://mariadb.com/kb/en/authentication-plugins/">https://mariadb.com/kb/en/authentication-plugins/</a></p><p><a href="https://mariadb.com/kb/en/caching_sha2_password-authentication-plugin/">https://mariadb.com/kb/en/caching_sha2_password-authentication-plugin/</a></p> Sun, 07 Mar 2021 16:36:08 GMT ttyS3 mariadbbinlog https://ttys3.dev/blog/setup-mariadb-replication-with-mariabackup Setup MariaDB Replication With MariaBackup https://ttys3.dev/blog/setup-mariadb-replication-with-mariabackup <h2 id="环境介绍"><a href="#环境介绍" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>环境介绍</h2><p>Server OS: CentOS 8.2 x64</p><p>MariaDB: 10.5.x (主 、从均运行在 Docker / Podman 容器里)</p><p>操作目标: 配置一台全新的从库</p><p>假设主库IP是 <strong>dbserver1</strong></p><p>从库IP是 <strong>dbserver2</strong></p><p>使用 MariaBackup 做全量或增量同步,更加方便。</p><h2 id="安装mariabackup"><a href="#安装mariabackup" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装MariaBackup</h2><p>首先我们需要在 <strong>主 / 从</strong> 服务器上分别安装 MariaBackup.</p><p>这里比较简单,参考<a href="https://mariadb.com/kb/en/mariabackup-overview/#installing-with-a-package-manager">官方文档</a>就好了。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># CentOS 8 / Stream</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> MariaDB-backup </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Debian / Ubuntu</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> mariadb-backup </span></code></pre></div><h2 id="准备全量同步备份文件"><a href="#准备全量同步备份文件" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>准备全量同步备份文件</h2><p>这里假设,master 机已经开启 binlog 和 master 模式。我们需要给整个库做一个备份。</p><p>由于我们是针对整个 master 服务器备份,因此这里没有指定 <code>--databases=数据名</code> 参数。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">mariabackup <span class="token variable parameter">--verbose</span> <span class="token variable parameter">--rsync</span> <span class="token variable parameter">--backup</span> <span class="token punctuation">\</span> </span><span class="code-line"> --target-dir<span class="token operator">=</span>/home/user001/backup/mysql/ <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">--host</span><span class="token operator">=</span>dbserver1 <span class="token variable parameter">--port</span><span class="token operator">=</span><span class="token number">3307</span> <span class="token variable parameter">--protocol</span><span class="token operator">=</span>tcp <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">--user</span><span class="token operator">=</span>root <span class="token variable parameter">--password</span><span class="token operator">=</span>root密码在这 </span></code></pre></div><p>这里一定会出错。 因为我们的 MariaDB 跑在容器里,host 机并不存在 <code>/var/lib/mysql</code> 目录。</p><p>解决办法是:</p><blockquote><p>Create a symlink on your host so that Mariabackup thinks<code>/var/lib/mysql</code> exists. Then delete the symlink once you&#x27;re done.</p></blockquote><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">ln</span> <span class="token variable parameter">-s</span> /home/user007/data/mysql /var/lib/mysql </span></code></pre></div><p>然后再运行命令,就OK了。如果备份成功,最后一部分的日志输出大概如下:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">Writing</span> xtrabackup_binlog_info </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token operator spread">...</span>done </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">Executing</span> <span class="token constant">FLUSH</span> <span class="token constant">NO_WRITE_TO_BINLOG</span> <span class="token constant">ENGINE</span> <span class="token constant">LOGS</span><span class="token operator spread">...</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token literal-property property">mariabackup</span><span class="token operator">:</span> <span class="token maybe-class-name">The</span> latest check <span class="token function">point</span> <span class="token punctuation">(</span><span class="token keyword control-flow">for</span> incremental<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token string">&#x27;2611384153422&#x27;</span> </span><span class="code-line"><span class="token literal-property property">mariabackup</span><span class="token operator">:</span> <span class="token maybe-class-name">Stopping</span> log copying thread<span class="token punctuation">.</span><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token operator">&gt;&gt;</span> log scanned up <span class="token function">to</span> <span class="token punctuation">(</span><span class="token number">2611437102980</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token operator">&gt;&gt;</span> log scanned up <span class="token function">to</span> <span class="token punctuation">(</span><span class="token number">2611437103220</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">Executing</span> <span class="token constant">BACKUP</span> <span class="token constant">STAGE</span> <span class="token constant">END</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">All</span> tables unlocked </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">Backup</span> created <span class="token keyword">in</span> directory <span class="token string">&#x27;/home/user007/backup/mysql/&#x27;</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">MySQL</span> binlog position<span class="token operator">:</span> filename <span class="token string">&#x27;master16-bin.003097&#x27;</span><span class="token punctuation">,</span> position <span class="token string">&#x27;15736398&#x27;</span><span class="token punctuation">,</span> <span class="token constant">GTID</span> <span class="token keyword">of</span> the last change <span class="token string">&#x27;0-101-9088409195&#x27;</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">Writing</span> backup<span class="token operator">-</span>my<span class="token punctuation">.</span><span class="token property-access">cnf</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token operator spread">...</span>done </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">Writing</span> xtrabackup_info </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token operator spread">...</span>done </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">58</span> <span class="token maybe-class-name">Redo</span> <span class="token function">log</span> <span class="token punctuation">(</span><span class="token keyword module">from</span> <span class="token constant">LSN</span> <span class="token number">2611376635865</span> to <span class="token number">2611437103220</span><span class="token punctuation">)</span> was copied<span class="token punctuation">.</span> </span><span class="code-line"><span class="token punctuation">[</span><span class="token number">00</span><span class="token punctuation">]</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">03</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">05</span><span class="token operator">:</span><span class="token number">54</span><span class="token operator">:</span><span class="token number">59</span> completed <span class="token constant">OK</span><span class="token operator">!</span> </span></code></pre></div><p>这样还没完,因为现在copy出来的备份文件,不能直接用于 MariaDB 恢复备份。</p><p>原因在<a href="https://mariadb.com/kb/en/mariabackup-options/#-prepare">这里</a>有解释:</p><blockquote><p>Prepares an existing backup to restore to the MariaDB Server.</p><p>Files that Mariabackup generates during <code>--backup</code> operations in the target directory are <strong>not ready</strong> for use on the Server. Before you can restore the data to MariaDB, <strong>you first need to prepare the backup</strong>.</p><p>In the case of <strong>full backups</strong>, the files are <strong>not point in time consistent</strong>, since they were taken at different times. If you try to restore the database without <strong>first preparing the data</strong>, InnoDB <strong>rejects</strong> the new data as <strong>corrupt</strong>. Running Mariabackup with the <code>--prepare</code> command readies the data so you can restore it to MariaDB Server. When working with <strong>incremental backups</strong>, you need to use the <code>--prepare</code> command and the <code>--incremental-dir</code> option to update <strong>the base backup</strong> with <strong>the deltas</strong> from an incremental backup.</p></blockquote><p>因此,对于增量备份的 prepare 操作,其实还需要加 <code>--incremental-dir</code> 选项。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">mariabackup <span class="token variable parameter">--prepare</span> <span class="token variable parameter">--verbose</span> <span class="token variable parameter">--rsync</span> --target-dir<span class="token operator">=</span>/home/user007/backup/mysql/ </span><span class="code-line"><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span> </span><span class="code-line"><span class="token number">2021</span>-03-04 <span class="token number">6</span>:02:53 <span class="token number">0</span> <span class="token punctuation">[</span>Note<span class="token punctuation">]</span> InnoDB: apply <span class="token number">2611435179079</span>: <span class="token punctuation">[</span>page id: <span class="token variable assign-left">space</span><span class="token operator">=</span><span class="token number">129</span>, page <span class="token variable assign-left">number</span><span class="token operator">=</span><span class="token number">2125</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token number">2021</span>-03-04 <span class="token number">6</span>:02:53 <span class="token number">0</span> <span class="token punctuation">[</span>Note<span class="token punctuation">]</span> InnoDB: apply <span class="token number">2611436322402</span>: <span class="token punctuation">[</span>page id: <span class="token variable assign-left">space</span><span class="token operator">=</span><span class="token number">129</span>, page <span class="token variable assign-left">number</span><span class="token operator">=</span><span class="token number">2177</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token number">2021</span>-03-04 <span class="token number">6</span>:02:53 <span class="token number">0</span> <span class="token punctuation">[</span>Note<span class="token punctuation">]</span> InnoDB: apply <span class="token number">2611436322402</span>: <span class="token punctuation">[</span>page id: <span class="token variable assign-left">space</span><span class="token operator">=</span><span class="token number">129</span>, page <span class="token variable assign-left">number</span><span class="token operator">=</span><span class="token number">2177</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token number">2021</span>-03-04 <span class="token number">6</span>:02:53 <span class="token number">0</span> <span class="token punctuation">[</span>Note<span class="token punctuation">]</span> InnoDB: apply <span class="token number">2611436391525</span>: <span class="token punctuation">[</span>page id: <span class="token variable assign-left">space</span><span class="token operator">=</span><span class="token number">129</span>, page <span class="token variable assign-left">number</span><span class="token operator">=</span><span class="token number">2177</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token number">2021</span>-03-04 <span class="token number">6</span>:02:53 <span class="token number">0</span> <span class="token punctuation">[</span>Note<span class="token punctuation">]</span> InnoDB: apply <span class="token number">2611436391525</span>: <span class="token punctuation">[</span>page id: <span class="token variable assign-left">space</span><span class="token operator">=</span><span class="token number">129</span>, page <span class="token variable assign-left">number</span><span class="token operator">=</span><span class="token number">2177</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token number">2021</span>-03-04 <span class="token number">6</span>:02:53 <span class="token number">0</span> <span class="token punctuation">[</span>Note<span class="token punctuation">]</span> InnoDB: apply <span class="token number">2611435179079</span>: <span class="token punctuation">[</span>page id: <span class="token variable assign-left">space</span><span class="token operator">=</span><span class="token number">129</span>, page <span class="token variable assign-left">number</span><span class="token operator">=</span><span class="token number">2125</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token number">2021</span>-03-04 <span class="token number">6</span>:02:53 <span class="token number">0</span> <span class="token punctuation">[</span>Note<span class="token punctuation">]</span> InnoDB: apply <span class="token number">2611435368189</span>: <span class="token punctuation">[</span>page id: <span class="token variable assign-left">space</span><span class="token operator">=</span><span class="token number">129</span>, page <span class="token variable assign-left">number</span><span class="token operator">=</span><span class="token number">2125</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token number">2021</span>-03-04 <span class="token number">6</span>:02:53 <span class="token number">0</span> <span class="token punctuation">[</span>Note<span class="token punctuation">]</span> InnoDB: apply <span class="token number">2611435368189</span>: <span class="token punctuation">[</span>page id: <span class="token variable assign-left">space</span><span class="token operator">=</span><span class="token number">129</span>, page <span class="token variable assign-left">number</span><span class="token operator">=</span><span class="token number">2125</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">[</span>00<span class="token punctuation">]</span> <span class="token number">2021</span>-03-04 06:02:53 Last binlog <span class="token function">file</span> , position <span class="token number">0</span> </span><span class="code-line"><span class="token punctuation">[</span>00<span class="token punctuation">]</span> <span class="token number">2021</span>-03-04 06:02:53 completed OK<span class="token operator">!</span> </span></code></pre></div><h2 id="复制备份文件到从库所在主机"><a href="#复制备份文件到从库所在主机" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>复制备份文件到从库所在主机</h2><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 首先 ssh 到从库机器, 准备好存放备份的目录</span> </span><span class="code-line"><span class="token function">mkdir</span> <span class="token variable parameter">-p</span> /home/user007/backup/mysql </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 其实我这里的机器并不是22端口</span> </span><span class="code-line"><span class="token comment"># 没错,当然是走内网地址</span> </span><span class="code-line"><span class="token function">rsync</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;ssh -p 2222&#x27;</span> <span class="token variable parameter">-avP</span> /home/user007/backup/mysql root@dbserver2:/home/user007/backup/ </span></code></pre></div><h2 id="准备好从库同步需要的账号"><a href="#准备好从库同步需要的账号" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>准备好从库同步需要的账号</h2><div class="relative"><pre><code class="code-highlight language-sql"><span class="code-line"><span class="token keyword">CREATE</span> <span class="token keyword">USER</span> <span class="token string">&#x27;replication_user&#x27;</span><span class="token variable">@&#x27;dbserver2&#x27;</span> IDENTIFIED <span class="token keyword">BY</span> <span class="token string">&#x27;password&#x27;</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">GRANT</span> <span class="token keyword">REPLICATION</span> SLAVE <span class="token keyword">ON</span> <span class="token operator">*</span><span class="token punctuation">.</span><span class="token operator">*</span> <span class="token keyword">TO</span> <span class="token string">&#x27;replication_user&#x27;</span><span class="token variable">@&#x27;dbserver2&#x27;</span><span class="token punctuation">;</span> </span></code></pre></div><h2 id="在新的从库上恢复备份"><a href="#在新的从库上恢复备份" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>在新的从库上恢复备份</h2><p>首先 <code>systemctl stop ctr-site007-mariadb</code> 停止掉 MariaDB 服务器, 准备恢复备份。</p><p>为什么不是 docker stop 或 podman stop ? 因为这个容器是用 podman generate 生成了 systemd unit 启动服务的,如果从 podman 停止, systemd 又会自动重启容器。所以,下面看到 systemctl 操作 ctr 开头的 service 时,请自行替换成你自己的命令。</p><p>恢复其实就是 copy 准备好的备份文件到 MariaDB <code>datadir</code> (也就是<code>/var/lib/mysql</code>)。</p><p>由于从为这边我们也是使用容器跑的 MariaDB, 因此同样要给做软链:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">ln</span> <span class="token variable parameter">-s</span> /home/user007/data/mysql /var/lib/mysql </span></code></pre></div><p>开始恢复备份文件:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">mariabackup --copy-back <span class="token variable parameter">--verbose</span> <span class="token variable parameter">--rsync</span> <span class="token punctuation">\</span> </span><span class="code-line"> --target-dir<span class="token operator">=</span>/home/user007/backup/mysql/ </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 相关日志输出</span> </span><span class="code-line"><span class="token punctuation">[</span>01<span class="token punctuation">]</span> <span class="token number">2021</span>-03-04 06:27:14 Copying ./xtrabackup_info to /var/lib/mysql/xtrabackup_info </span><span class="code-line"><span class="token punctuation">[</span>01<span class="token punctuation">]</span> <span class="token number">2021</span>-03-04 06:27:14 <span class="token punctuation">..</span>.done </span><span class="code-line"><span class="token punctuation">[</span>00<span class="token punctuation">]</span> <span class="token number">2021</span>-03-04 06:27:14 completed OK<span class="token operator">!</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 检查下恢复的文件</span> </span><span class="code-line"><span class="token punctuation">[</span>root@replica mysql<span class="token punctuation">]</span><span class="token comment"># ls /var/lib/mysql/</span> </span><span class="code-line">aria_log.00000001 aria_log_control ib_buffer_pool ibdata1 mysql performance_schema site007_prod xtrabackup_info </span></code></pre></div><p>注意,执行这个操作的前提是 <code>/var/lib/mysql</code> 目录是空的。也就是如果是我们新跑的服务器,里面没数据的,我们也要清空这个目录, 不然 MariaBackup 不会执行恢复备份的操作 (会有错误: Original data directory /var/lib/mysql is not empty!)。</p><p>根据情况的不同,可能还要恢复一下文件权限,比如 <code>chown -R mysql:mysql /var/lib/mysql/</code></p><p>查看一下 <code>xtrabackup_binlog_info</code> 这个文件的内容,这里第三个值 <code>0-101-9090487761</code> 就是 <code>GTID</code>, copy出来先找个地方暂存一下,等会要用:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token punctuation">[</span>root@replica mysql<span class="token punctuation">]</span><span class="token comment"># cat xtrabackup_binlog_info</span> </span><span class="code-line">master16-bin.003097 <span class="token number">775477086</span> <span class="token number">0</span>-101-9090487761 </span></code></pre></div><h2 id="开启从库同步"><a href="#开启从库同步" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>开启从库同步</h2><p>启动从服务器: <code>systemctl start ctr-site007-mariadb</code></p><p>登录从库<code>mysql -u root -h dbserver2 -P 3307 -p</code>:</p><div class="relative"><pre><code class="code-highlight language-sql"><span class="code-line">STOP SLAVE<span class="token punctuation">;</span> </span><span class="code-line">RESET SLAVE<span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">SET</span> <span class="token keyword">GLOBAL</span> gtid_slave_pos <span class="token operator">=</span> <span class="token string">&quot;0-101-9090487761&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">CHANGE MASTER <span class="token keyword">TO</span> </span><span class="code-line"> MASTER_HOST<span class="token operator">=</span><span class="token string">&#x27;dbserver1&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> MASTER_USER<span class="token operator">=</span><span class="token string">&#x27;replication_user&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> MASTER_PASSWORD<span class="token operator">=</span><span class="token string">&#x27;主库同步密码&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> MASTER_PORT<span class="token operator">=</span><span class="token number">3307</span><span class="token punctuation">,</span> </span><span class="code-line"> MASTER_CONNECT_RETRY<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> </span><span class="code-line"> MASTER_USE_GTID<span class="token operator">=</span>slave_pos<span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">START</span> SLAVE<span class="token punctuation">;</span> </span></code></pre></div><p>查看一下同步状态是否正常:</p><p>比较需要关注的几个选项:</p><p><strong>Slave_IO_State</strong>: Queueing master event to the relay log</p><p><strong>Master_Log_File</strong>: master16-bin.003097 Read_Master_Log_Pos: 842451034 Relay_Log_File: master94-relay-bin.000002 Relay_Log_Pos: 649307</p><p><strong>Slave_IO_Running</strong>: Yes Slave_SQL_Running: Yes</p><p><strong>Using_Gtid</strong>: Slave_Pos Gtid_IO_Pos: 0-101-9090669366</p><p><strong>Seconds_Behind_Master</strong>: 301</p><p><code>Seconds_Behind_Master</code> 是最重要的一个参数。300多秒的延时对于一般的同步来说算是问题比较大了,但是这里由于我们是刚刚启动复制,才开始第一次同步,因此这个情况是正常的。过一会这个值就会正常了(正常来说应该是接近0)。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">MariaDB <span class="token punctuation">[</span><span class="token punctuation">(</span>none<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> SHOW SLAVE STATUS<span class="token punctuation">\</span>G </span><span class="code-line">*************************** <span class="token number">1</span>. row *************************** </span><span class="code-line"> Slave_IO_State: Queueing master event to the relay log </span><span class="code-line"> Master_Host: dbserver1 </span><span class="code-line"> Master_User: replication_user </span><span class="code-line"> Master_Port: <span class="token number">3307</span> </span><span class="code-line"> Connect_Retry: <span class="token number">10</span> </span><span class="code-line"> Master_Log_File: master16-bin.003097 </span><span class="code-line"> Read_Master_Log_Pos: <span class="token number">842451034</span> </span><span class="code-line"> Relay_Log_File: master94-relay-bin.000002 </span><span class="code-line"> Relay_Log_Pos: <span class="token number">649307</span> </span><span class="code-line"> Relay_Master_Log_File: master16-bin.003097 </span><span class="code-line"> Slave_IO_Running: Yes </span><span class="code-line"> Slave_SQL_Running: Yes </span><span class="code-line"> Replicate_Do_DB: site007_prod </span><span class="code-line"> Replicate_Ignore_DB: </span><span class="code-line"> Replicate_Do_Table: </span><span class="code-line"> Replicate_Ignore_Table: </span><span class="code-line"> Replicate_Wild_Do_Table: </span><span class="code-line"> Replicate_Wild_Ignore_Table: </span><span class="code-line"> Last_Errno: <span class="token number">0</span> </span><span class="code-line"> Last_Error: </span><span class="code-line"> Skip_Counter: <span class="token number">0</span> </span><span class="code-line"> Exec_Master_Log_Pos: <span class="token number">776125657</span> </span><span class="code-line"> Relay_Log_Space: <span class="token number">66974795</span> </span><span class="code-line"> Until_Condition: None </span><span class="code-line"> Until_Log_File: </span><span class="code-line"> Until_Log_Pos: <span class="token number">0</span> </span><span class="code-line"> Master_SSL_Allowed: No </span><span class="code-line"> Master_SSL_CA_File: </span><span class="code-line"> Master_SSL_CA_Path: </span><span class="code-line"> Master_SSL_Cert: </span><span class="code-line"> Master_SSL_Cipher: </span><span class="code-line"> Master_SSL_Key: </span><span class="code-line"> Seconds_Behind_Master: <span class="token number">301</span> </span><span class="code-line"> Master_SSL_Verify_Server_Cert: No </span><span class="code-line"> Last_IO_Errno: <span class="token number">0</span> </span><span class="code-line"> Last_IO_Error: </span><span class="code-line"> Last_SQL_Errno: <span class="token number">0</span> </span><span class="code-line"> Last_SQL_Error: </span><span class="code-line"> Replicate_Ignore_Server_Ids: </span><span class="code-line"> Master_Server_Id: <span class="token number">101</span> </span><span class="code-line"> Master_SSL_Crl: </span><span class="code-line"> Master_SSL_Crlpath: </span><span class="code-line"> Using_Gtid: Slave_Pos </span><span class="code-line"> Gtid_IO_Pos: <span class="token number">0</span>-101-9090669366 </span><span class="code-line"> Replicate_Do_Domain_Ids: </span><span class="code-line"> Replicate_Ignore_Domain_Ids: </span><span class="code-line"> Parallel_Mode: optimistic </span><span class="code-line"> SQL_Delay: <span class="token number">0</span> </span><span class="code-line"> SQL_Remaining_Delay: NULL </span><span class="code-line"> Slave_SQL_Running_State: init <span class="token keyword">for</span> update </span><span class="code-line"> Slave_DDL_Groups: <span class="token number">0</span> </span><span class="code-line">Slave_Non_Transactional_Groups: <span class="token number">0</span> </span><span class="code-line"> Slave_Transactional_Groups: <span class="token number">1765</span> </span><span class="code-line"><span class="token number">1</span> row <span class="token keyword">in</span> <span class="token builtin class-name">set</span> <span class="token punctuation">(</span><span class="token number">0.000</span> sec<span class="token punctuation">)</span> </span></code></pre></div><h2 id="misc"><a href="#misc" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Misc</h2><h3 id="error-1198"><a href="#error-1198" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>ERROR 1198</h3><blockquote><p>ERROR 1198 (HY000): This operation cannot be performed as you have a running slave &#x27;&#x27;; run STOP SLAVE &#x27;&#x27; first</p></blockquote><p>这个错误一般出现在 CHANGE MASTER TO ... 配置slave时。原因是前面的 slave 配置还在,STOP SLAVE 然后 RESET SLAVE 再执行 CHANGE MASTER TO ... 就好了。</p><h3 id="error-1932"><a href="#error-1932" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>ERROR 1932</h3><blockquote><p>#1932 - Table &#x27;site007_prod.users&#x27; doesn&#x27;t exist in engine</p><p>Copy the ib_logfileXX and ibdata file from old mysql/data folder to the new mysql data folder and it will fix the issue</p></blockquote><p>这个主要是没有使用 MariaBackup 恢复备份,而是采用 rsync 手动 copy 文件到 MairaDB datadir 下的。</p><p>并且,少复制了 ib_logfileXX 和 ibdata 等文件。所以,还是用 MariaBackup 恢复的好,除非你非常了解 MariaBackup 的工作原理。</p><h3 id="如何安全地清理-binlog"><a href="#如何安全地清理-binlog" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何安全地清理 binlog</h3><p>这里主要是讲主库的binlog (从库一般不再作为别人的主,我们不开)</p><p>命令格式:</p><div class="relative"><pre><code class="code-highlight language-sql"><span class="code-line"><span class="token keyword">PURGE</span> { <span class="token keyword">BINARY</span> <span class="token operator">|</span> MASTER } LOGS { <span class="token keyword">TO</span> <span class="token string">&#x27;log_name&#x27;</span> <span class="token operator">|</span> BEFORE datetime_expr } </span></code></pre></div><blockquote><p>The PURGE BINARY LOGS statement deletes all the binary log files listed in the log index file <strong>prior to the specified log file name or date</strong>. BINARY and MASTER are <strong>synonyms</strong>.</p><p><strong>Deleted log files also are removed from the list recorded in the index file, so that the given log file becomes the first in the list.</strong> The datetime expression is in the format &#x27;<strong>YYYY-MM-DD hh:mm:ss</strong>&#x27;.</p></blockquote><p>注意这里是 <strong>prior to (<strong>在…之前</strong>)</strong>, 首先我们要检查从库最慢的那个节点(假设有多个从库的话)的同步情况,比如<strong>Slave status</strong>中的 <strong>Master_Log_File</strong> = <code>master16-bin.003103</code></p><p>Relay_Log_File master94-relay-bin.000015</p><p><strong>Relay_Master_Log_File master16-bin.003103</strong></p><p>表示当前 slave 正在 replicate master 那边的 <strong>master16-bin.003103</strong>, 因此, master 那边可以清空 在 <strong>master16-bin.003103 之前</strong>的所有 binlog 文件:</p><div class="relative"><pre><code class="code-highlight language-sql"><span class="code-line"><span class="token keyword">PURGE</span> <span class="token keyword">BINARY</span> LOGS <span class="token keyword">TO</span> <span class="token string">&#x27;master16-bin.003103&#x27;</span> </span></code></pre></div><h3 id="如何使用-podman-生成-systemd-unit-文件"><a href="#如何使用-podman-生成-systemd-unit-文件" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何使用 podman 生成 systemd unit 文件</h3><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token builtin class-name">cd</span> /etc/systemd/system/ </span><span class="code-line"> </span><span class="code-line"><span class="token function">podman</span> generate systemd <span class="token variable parameter">--new</span> <span class="token variable parameter">-t</span> <span class="token number">10</span> <span class="token punctuation">\</span> </span><span class="code-line">--container-prefix ctr <span class="token variable parameter">-f</span> <span class="token variable parameter">-n</span> site007-mariadb </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 启用并启动服务</span> </span><span class="code-line">systemctl <span class="token builtin class-name">enable</span> <span class="token variable parameter">--now</span> ctr-site007-mariadb </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p>本文主要参考: <a href="https://mariadb.com/kb/en/setting-up-a-replication-slave-with-mariabackup/">https://mariadb.com/kb/en/setting-up-a-replication-slave-with-mariabackup/</a></p><p>expire_logs_days 配置: <a href="https://mariadb.com/kb/en/replication-and-binary-log-system-variables/#expire_logs_days">https://mariadb.com/kb/en/replication-and-binary-log-system-variables/#expire_logs_days</a></p><p>显示从服务器: <a href="https://mariadb.com/kb/en/show-replica-hosts/">https://mariadb.com/kb/en/show-replica-hosts/</a></p><p>关于使用 GTID: <a href="https://mariadb.com/kb/en/gtid/#using-global-transaction-ids">https://mariadb.com/kb/en/gtid/#using-global-transaction-ids</a></p><p>MySQL 复制常见误区: <a href="https://severalnines.com/blog/top-mistakes-avoid-mysql-replication">https://severalnines.com/blog/top-mistakes-avoid-mysql-replication</a></p><p><a href="https://mariadb.com/kb/en/setting-up-replication/">https://mariadb.com/kb/en/setting-up-replication/</a></p><p><a href="https://alibaba-cloud.medium.com/how-to-setup-mariadb-master-and-slave-replication-on-ubuntu-16-04-850c155c5481">https://alibaba-cloud.medium.com/how-to-setup-mariadb-master-and-slave-replication-on-ubuntu-16-04-850c155c5481</a></p><p>MariaBackup 相关文档:</p><p>安装:<a href="https://mariadb.com/kb/en/mariabackup-overview/#installing-with-a-package-manager"> https://mariadb.com/kb/en/mariabackup-overview/#installing-with-a-package-manager</a></p><p>MariaBackup 选项: <a href="https://mariadb.com/kb/en/mariabackup-options/">https://mariadb.com/kb/en/mariabackup-options/</a></p><p>MariaBackup 概览: <a href="https://mariadb.com/kb/en/mariabackup-overview/">https://mariadb.com/kb/en/mariabackup-overview/</a></p><p>MariaBackup 工作原理之初始化: <a href="https://mariadb.com/kb/en/how-mariabackup-works/#initialization-phase">https://mariadb.com/kb/en/how-mariabackup-works/#initialization-phase</a></p><p>解决 MariaBackup 针对 MariaDB 容器备份时遇到的问题 <a href="https://dba.stackexchange.com/questions/234586/mariabackup-of-database-running-in-docker">https://dba.stackexchange.com/questions/234586/mariabackup-of-database-running-in-docker</a></p><p>如何安全地清理binlog:</p><p><a href="https://minervadb.com/index.php/2018/05/14/purging-binary-logs-from-mysql-master-safely/">https://minervadb.com/index.php/2018/05/14/purging-binary-logs-from-mysql-master-safely/</a></p><p><a href="https://mariadb.com/kb/en/purge-binary-logs/">https://mariadb.com/kb/en/purge-binary-logs/</a></p><p>innodb 如何只恢复特定的表:</p><p>首先使用 MariaBackup 在 <code>prepare</code> 的时候 增加<code> --export</code> 参数:</p><p><a href="https://mariadb.com/kb/en/restoring-individual-tables-and-partitions-with-mariabackup/">https://mariadb.com/kb/en/restoring-individual-tables-and-partitions-with-mariabackup/</a></p><p>然后 Importing Transportable Tablespaces for Non-partitioned Tables <a href="https://mariadb.com/kb/en/innodb-file-per-table-tablespaces/#importing-transportable-tablespaces-for-non-partitioned-tables">https://mariadb.com/kb/en/innodb-file-per-table-tablespaces/#importing-transportable-tablespaces-for-non-partitioned-tables</a></p><p>部分备份:</p><p><a href="https://mariadb.com/kb/en/partial-backup-and-restore-with-mariabackup/">https://mariadb.com/kb/en/partial-backup-and-restore-with-mariabackup/</a></p><p>进一步了解Mariabackup:</p><p>Mariabackup备份的文件: <a href="https://mariadb.com/kb/en/files-backed-up-by-mariabackup/">https://mariadb.com/kb/en/files-backed-up-by-mariabackup/</a></p><p>Mariabackup创建的文件: <a href="https://mariadb.com/kb/en/files-created-by-mariabackup/">https://mariadb.com/kb/en/files-created-by-mariabackup/</a></p> Sun, 07 Mar 2021 10:43:50 GMT ttyS3 https://ttys3.dev/blog/apple-music-electron Apple Music Electron https://ttys3.dev/blog/apple-music-electron <p>正如 Apple-Music-Electron repo 上简介里说的:</p><blockquote><p>适用于Windows,Linux和macOS的非官方Apple Music应用程序,而无需安装iTunes或通过浏览器使用极其臃肿的Web应用程序。</p></blockquote><p>这也是老灯在 Linux 下要这么一个 app 的原因。对于老灯来说,浏览器在大部分情况下都是用来浏览文档,调试代码。里面夹杂着一个在线音乐播放网站可不好找,特别是tab非常多的情况下。因此,有一个独立的 app 就非常重要的。哪怕只是拿 Electron 框架包裹一下 <a href="https://beta.music.apple.com/">https://beta.music.apple.com/</a> , 老灯也觉得这类 app 非常有意义。Life changed.</p><h2 id="功能简介"><a href="#功能简介" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>功能简介</h2><p>在 Github 上找到两个, 分别只有30多和10多个star, 两个老灯都试用了一下。</p><p>安装就不说了哈,直接 Github release 里下载相应的 rpm 或 deb 包安装即可。</p><h3 id="cryptofyreapple-music-electron"><a href="#cryptofyreapple-music-electron" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>cryptofyre/Apple-Music-Electron</h3><p><a href="https://github.com/cryptofyre/Apple-Music-Electron">https://github.com/cryptofyre/Apple-Music-Electron</a> 各方面都比较出色,黑色界面,唯一的缺点是没有竖直滚动条。顶部播放条的艺人名称和歌曲名称可点击。老灯选择的是这个。</p><div><img alt="" src="https://ttys3.dev/static/assets/apple-music-electron-dark-version-S33J4BH7.jpg" width="1513" height="1080"/></div><div><img alt="" src="https://ttys3.dev/static/assets/apple-music-electron-dark-version-browse-XUDKD5NO.jpg" width="1651" height="1080"/></div><div><img alt="" src="https://ttys3.dev/static/assets/apple-music-electron-dark-album-YDROXC5C.jpg" width="1651" height="1080"/></div><h3 id="17hoehbrapple-music-electron"><a href="#17hoehbrapple-music-electron" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>17hoehbr/apple-music-electron</h3><p><a href="https://github.com/17hoehbr/apple-music-electron">https://github.com/17hoehbr/apple-music-electron</a> 直接套用了 <a href="https://beta.music.apple.com/">https://beta.music.apple.com/</a> 的主题,有竖直滚动条。缺点是顶部播放条的艺人名称和歌曲名称无法点击。</p><div><img alt="" src="https://ttys3.dev/static/assets/apple-music-electron-QNCYNHUR.jpg" width="1414" height="1080"/></div><h2 id="troublesoot"><a href="#troublesoot" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>troublesoot</h2><h3 id="点击播放时弹出content_equivalent错误"><a href="#点击播放时弹出content_equivalent错误" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>点击播放时弹出<code>CONTENT_EQUIVALENT</code>错误</h3><p>解决办法: 重启 app 就好了。</p><p>原因是,Apple Music 使用了DRM加密, Electron wrapper 在首次启动的时候需要联网下载一个 <code>Widevine DRM</code> 解密模块。重启启动 app , 一般 libwidevinecdm.so 下载成功了,就可以正常播放了。</p><p>你可以通过查看 <code>~/.config/Apple Music/WidevineCDM</code> 目录下的文件检测 DRM 模块是否下载成功。如:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">ls</span> <span class="token variable parameter">-lh</span> ~/.config/Apple Music/WidevineCDM </span><span class="code-line">.rw-r--r-- ttys3 ttys3 <span class="token number">8.9</span> MB Sun Mar <span class="token number">7</span> <span class="token number">11</span>:41:14 <span class="token number">2021</span>  libwidevinecdm.so </span><span class="code-line">.rw-r--r-- ttys3 ttys3 <span class="token number">479</span> B Sun Mar <span class="token number">7</span> <span class="token number">11</span>:41:14 <span class="token number">2021</span>  LICENSE.txt </span><span class="code-line">.rw-r--r-- ttys3 ttys3 <span class="token number">375</span> B Sun Mar <span class="token number">7</span> <span class="token number">11</span>:41:14 <span class="token number">2021</span>  manifest.json </span><span class="code-line">❯ bat manifest.json </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token string">&quot;arch&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;x64&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;description&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;Widevine Content Decryption Module&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;manifest_version&quot;</span><span class="token builtin class-name">:</span> <span class="token number">2</span>, </span><span class="code-line"> <span class="token string">&quot;name&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;WidevineCdm&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;os&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;linux&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;version&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;4.10.1582.2&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;x-cdm-codecs&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;vp8,vp9.0,avc1,av01&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;x-cdm-host-versions&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;10&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;x-cdm-interface-versions&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;10&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;x-cdm-module-versions&quot;</span><span class="token builtin class-name">:</span> <span class="token string">&quot;4&quot;</span>, </span><span class="code-line"> <span class="token string">&quot;x-cdm-persistent-license-support&quot;</span><span class="token builtin class-name">:</span> <span class="token boolean">true</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> ~/.config/Apple Music/WidevineCDM </span></code></pre></div><h3 id="failed-to-install-widevine-component-error-400"><a href="#failed-to-install-widevine-component-error-400" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Failed to install Widevine component, Error 400</h3><p>一般是由于网络问题,导致 Electronjs 自动下载 Widevine DRM 组件失败。</p><p>在安装了 Chrome 的 Linux 机器上,直接Copy Chrome 自带的 Widevine 组件即可.</p><p>在 Ubuntu 上这个位置是:</p><p><code>/opt/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so</code></p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 先启动一次 app</span> </span><span class="code-line"><span class="token comment"># 然后创建目录 WidevineCDM</span> </span><span class="code-line"><span class="token function">mkdir</span> ~/.config/Apple<span class="token punctuation">\</span> Music/WidevineCDM/ </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">cp</span> <span class="token variable parameter">-v</span> /opt/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so ~/.config/Apple<span class="token punctuation">\</span> Music/WidevineCDM/ </span><span class="code-line"><span class="token string">&#x27;/opt/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so&#x27;</span> -<span class="token operator">&gt;</span> &#x27;/home/ttys3/.config/Apple Music/WidevineCDM/libwidevinecdm.so </span></code></pre></div><p>Chrome 打开 chrome://components/ 查看 “<strong>Widevine Content Decryption Module</strong>” 的版本号,老灯这里是“Version: <code>4.10.2209.0</code>”</p><p>然后在 <code>~/.config/Apple Music/WidevineCDM</code> 下新建 <code>manifest.json</code> 内容如下:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;arch&quot;</span><span class="token operator">:</span> <span class="token string">&quot;x64&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;description&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Widevine Content Decryption Module&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;manifest_version&quot;</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;WidevineCdm&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;os&quot;</span><span class="token operator">:</span> <span class="token string">&quot;linux&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;version&quot;</span><span class="token operator">:</span> <span class="token string">&quot;4.10.2209.0&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;x-cdm-codecs&quot;</span><span class="token operator">:</span> <span class="token string">&quot;vp8,vp9.0,avc1,av01&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;x-cdm-host-versions&quot;</span><span class="token operator">:</span> <span class="token string">&quot;10&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;x-cdm-interface-versions&quot;</span><span class="token operator">:</span> <span class="token string">&quot;10&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;x-cdm-module-versions&quot;</span><span class="token operator">:</span> <span class="token string">&quot;4&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;x-cdm-persistent-license-support&quot;</span><span class="token operator">:</span> <span class="token boolean">true</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>启动一次 app, 然后关闭,再启动 就 OK 了。</p><h3 id="已经播放过的歌曲缓存在哪里"><a href="#已经播放过的歌曲缓存在哪里" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>已经播放过的歌曲缓存在哪里?</h3><p>经过老灯的分析,这个目录是在 <code>~/.config/Apple Music/Cache</code></p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">ncdu <span class="token number">1.15</span>.1 ~ Use the arrow keys to navigate, press ? <span class="token keyword">for</span> <span class="token builtin class-name">help</span> </span><span class="code-line">--- /home/ttys3/.config/Apple Music --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- </span><span class="code-line"> <span class="token number">305.0</span> MiB <span class="token punctuation">[</span><span class="token comment">##########] /Cache</span> </span><span class="code-line"> <span class="token number">28.9</span> MiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /Service Worker </span><span class="code-line"> <span class="token number">8.9</span> MiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /WidevineCDM </span><span class="code-line"> <span class="token number">2.2</span> MiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /Code Cache </span><span class="code-line"> <span class="token number">448.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /Dictionaries </span><span class="code-line"> <span class="token number">300.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /GPUCache </span><span class="code-line"> <span class="token number">120.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /File System </span><span class="code-line"> <span class="token number">108.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /IndexedDB </span><span class="code-line"> <span class="token number">52.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> QuotaManager </span><span class="code-line"> <span class="token number">40.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /Local Storage </span><span class="code-line"> <span class="token number">32.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /databases </span><span class="code-line"> <span class="token number">28.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> Cookies </span><span class="code-line"> <span class="token number">28.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /Session Storage </span><span class="code-line"> <span class="token number">8.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /blob_storage </span><span class="code-line"> <span class="token number">8.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /Downloads </span><span class="code-line"> <span class="token number">8.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> TransportSecurity </span><span class="code-line">e <span class="token number">4.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> /Crash Reports </span><span class="code-line"> <span class="token number">4.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> Network Persistent State </span><span class="code-line"> <span class="token number">4.0</span> KiB <span class="token punctuation">[</span> <span class="token punctuation">]</span> Preferences </span><span class="code-line"> <span class="token number">0.0</span> B <span class="token punctuation">[</span> <span class="token punctuation">]</span> QuotaManager-journal </span><span class="code-line"> <span class="token number">0.0</span> B <span class="token punctuation">[</span> <span class="token punctuation">]</span> Cookies-journal </span></code></pre></div><h3 id="我的系统是英文界面的如何强制-apple-music-显示中文"><a href="#我的系统是英文界面的如何强制-apple-music-显示中文" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>我的系统是英文界面的,如何强制 Apple Music 显示中文?</h3><p>这其实是老灯的需求,系统语言习惯设置成英文。但是,对于一些奇怪的歌曲名称,尤其是中国传统民族乐器经典曲目,我相信没几个人看到英文名称能翻译成中文。</p><p>这个也简单,修改启动命令,添加 <code>LANG=zh_CN.UTF-8</code> 环境变量即可。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">sed</span> <span class="token variable parameter">-i</span> <span class="token string">&#x27;s|Exec=&quot;/opt|Exec=env LANG=zh_CN.UTF-8 &quot;/opt|&#x27;</span> /usr/share/applications/apple-music-electron.desktop </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">❯ bat /usr/share/applications/apple-music-electron.desktop </span><span class="code-line"><span class="token punctuation">[</span>Desktop Entry<span class="token punctuation">]</span> </span><span class="code-line"><span class="token variable assign-left">Name</span><span class="token operator">=</span>Apple Music </span><span class="code-line"><span class="token variable assign-left">Exec</span><span class="token operator">=</span>env <span class="token variable assign-left"><span class="token constant environment">LANG</span></span><span class="token operator">=</span>zh_CN.UTF-8 <span class="token string">&quot;/opt/Apple Music/apple-music-electron&quot;</span> %U </span><span class="code-line"><span class="token variable assign-left">Terminal</span><span class="token operator">=</span>false </span><span class="code-line"><span class="token variable assign-left">Type</span><span class="token operator">=</span>Application </span><span class="code-line"><span class="token variable assign-left">Icon</span><span class="token operator">=</span>apple-music-electron </span><span class="code-line"><span class="token variable assign-left">StartupWMClass</span><span class="token operator">=</span>Apple Music </span><span class="code-line"><span class="token variable assign-left">Comment</span><span class="token operator">=</span>Unofficial Electron wrapper <span class="token keyword">for</span> Apple Music created by @cryptofyre </span><span class="code-line"><span class="token variable assign-left">Categories</span><span class="token operator">=</span>AudioVideo<span class="token punctuation">;</span> </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p>Widevine DRM 介绍 <a href="Widevine">https://zh.wikipedia.org/wiki/Widevine</a></p><p>关于 DRM 音频转换成 mp3 或 flac, 好像工具挺多的,比如 <a href="https://www.tunefab.com/zh-CN/am-converter/">TuneFab iTunes Audio Converter</a> (收费)</p> Sun, 07 Mar 2021 07:04:47 GMT ttyS3 apple-musiclinuxelectron https://ttys3.dev/blog/the-good-and-the-bad-of-fedora-linux The Good and The Bad of Fedora Linux https://ttys3.dev/blog/the-good-and-the-bad-of-fedora-linux <h2 id="the-good"><a href="#the-good" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>The good</h2><ol><li><p><a href="https://fedoraproject.org/wiki/Features/Presto">DeltaRPM</a> 是个好东西,可以节省更新的流量和本地cache的package空间</p><p><a href="https://en.wikipedia.org/wiki/Fedora_Linux" title="Fedora Linux">Fedora Linux</a> has supported binary delta updates by default using the <a href="https://en.wikipedia.org/wiki/Yellowdog_Updater,_Modified" title="Yellowdog Updater, Modified">yum</a> presto plugin since June 2009. This is based on <a href="https://en.wikipedia.org/wiki/RPM_Package_Manager" title="RPM Package Manager">RPM Package Manager</a>&#x27;s deltarpm system (2004), which was in turn based on bsdiff.[[1]](<a href="https://en.wikipedia.org/wiki/Delta_update#cite_note-1">https://en.wikipedia.org/wiki/Delta_update#cite_note-1</a>) </p><p><a href="https://en.wikipedia.org/wiki/Delta_update">https://en.wikipedia.org/wiki/Delta_update</a></p><p>然而Arch做了与这个相反的操作,把pacman的<a href="https://git.archlinux.org/pacman.git/commit/?id=c0e9be7973be6c81b22fde91516fb8991e7bb07b">delta功能移除</a>了。see <a href="https://www.reddit.com/r/archlinux/comments/b7zkg5/why_delta_support_removed_from_pacman/">Why delta support removed from pacman?</a></p><blockquote><p>Because no one really used it pretty much ever.To an extent, yes. But the official repo maintainers decided it was not worth the effort, so they didn&#x27;t do it.I&#x27;ve got to say - if you&#x27;re living in a developing country with shitty internet, Arch <em>might</em> not be the best option for you anyway.</p></blockquote><p>啥?发展中国家?哈哈,中招了。不过我们现在的网络,跑个Arch更新完全没问题了。 ps: 关于不使用 delta 更新的问题,我觉得 Arch 是对的。引入 delta 同时会引入其它问题,比如patch的时候会需要更多cpu算力,生成 delta 包时也需要更多的算力。</p><blockquote><p>Overcomplicating pacman and package mirrors for minor bandwith gain kinda defeats the KISS principle of arch</p></blockquote></li><li><p>软件包很新,可能没有ArchLinux新,但是肯定比Ubuntu/Debian这种喜欢用一些古董包的发行版要新(作为一个ArchLinux用户而方,by the way, 请原文我说Ubuntu/Debian用古董包)。</p></li><li><p>稳定的发布周期:<a href="https://fedoraproject.org/wiki/Fedora_Release_Life_Cycle#Development_Schedule">每六个月定期发布</a></p></li><li><p>有<a href="https://fedoramagazine.org/">官方博客</a>,时不时会发一些有意思的教程。</p></li><li><p>背后有Redhat的支持</p></li><li><p>相比于Ubuntu完全受*<a href="https://canonical.com/">Canonical</a>的控制, Fedora是一个<a href="https://en.wikipedia.org/wiki/List_of_Linux_distributions#Fedora-based">完完全全的社区支持的系统</a>*</p></li><li><p><em>自带</em>大型的软件包仓库,包数量众多(不像Ubuntu,全靠ppa撑场子)</p></li><li><p>得益于rpm包的流行程度,基本上大部分厂家或Github项目(如果有提供包),都会直接提供rpm包供用户下载</p></li><li><p>官方同时提供Workstation/Server/IoT版的iso安装镜像,同时还有Fedora CoreOS和Fedora Silverblue</p></li><li><p>多DE支持,官方除了支持GNOME3(默认选项),还有可以在<a href="https://spins.fedoraproject.org/">Fedora Spins</a> 下载到KDE,XFCE , LXQt, MATE Compiz, LXDE 和 <em>Sugar on a stick</em> (SOAS) 版。</p></li><li><p>自带SeLinux支持且默认开启,安全性没得说</p></li><li><p>对红帽系的很多东西天生支持就很好,比如FirewallD, Kvm-qemu, Cockpit</p></li><li><p>开发活跃,引领潮流。比如Fedora最先引入systemd的,后面又率先启用了EarlyOOM功能,默认启用fstrim.timer,用Geary替换了很多发行版中万年不变的Evolution邮件客户端,firewalld默认使用nftables后端, 让Python 2 彻底退休,用更安全的lchsh 代替了chsh, 默认启用 CGroup v2。rpm package压缩算法从xz level 2切换到zstd compression level 19了(从f31起)。当很多发行版还在用ext4时,f33已经将家用版的默认文件系统改成了btrfs。 f34据说要默认开启btrfs的zstd透明压缩功能</p></li><li><p>每一次新的版本发布之前,你都可以从官方wiki的 <a href="https://fedoraproject.org/wiki/Changes">Change Set</a> 看到完整的变更记录以及为什么要这样做的理由。相比于某些发行版一声不响就把东西改了,Fedora这种操作显得非常专业和规范。比如f34准备抛弃PulseAudio and JACK并切换到<a href="https://fedoraproject.org/wiki/Changes/DefaultPipeWire" title="Changes/DefaultPipeWire"></a><a href="https://fedoraproject.org/wiki/Changes/DefaultPipeWire" title="Changes/DefaultPipeWire"></a><a href="https://fedoraproject.org/wiki/Changes/DefaultPipeWire" title="Changes/DefaultPipeWire">PipeWire</a></p></li><li><p>基于图片界面的<a href="https://github.com/rhinstaller/anaconda"> Anaconda System installer</a> 使用起来非常方便,尤其是磁盘分区功能非常好用。Anaconda 安装完后系统后会自动生成 kickstart 脚本,方便二次安装或批量自动化安装。</p></li><li><p>官方明确支持<a href="https://fedoraproject.org/wiki/Licensing:WTFPL?rd=Licensing/WTFPL"> Do What The Fuck You Want To Public License (WTFPL)</a></p></li><li><p>Fedora 上的 <a href="https://wiki.gnome.org/Apps/Software">GNOME Software</a> 是原版的, 如果有需要,你可以自行添加添加flatpak源。(不会像 Ubuntu 一样用 <em><a href="https://canonical.com/">Canonical</a></em> 自家的软件中心强制用户只能安装snap app)</p></li></ol><h2 id="the-bad"><a href="#the-bad" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>The bad</h2><ol><li><p>社区论坛需要使用Fedora官方的Fedora Account System (FAS) account进行登录。作为一个习惯了使用Github/Gitlab或Google账号一键登录的人,直接导致了我点击了浏览器的x按钮关闭页面,因为我不想浪费太多时间在注册账号这种事情上。</p><p>比如有个人问如何在Fedora上使用百度网盘(因为Fedora和Arch的openssl包都很新,百度那破玩意一跑就崩),我很想帮助他,因为我研究之后,成功地正常运行了。但是当我点击登录的时候,我被重定向到了Fedora Account System (FAS) account,没有使用其它社交账号登录的按钮。这其实也很正常,因为Fedora一直坚持FOSS的理念。使用一个商业公司的账号体系来登录,有违FOSS精神。</p></li><li><p>Fedora非常提倡FOSS,版权策略简直应用到了变态的地步。比如官方仓库里的p7zip包,因为p7zip官方源码里包含了未经授权的rar相关代码,Fedora直接<a href="https://src.fedoraproject.org/rpms/p7zip/blob/f33/f/p7zip_15.14-norar_cmake.patch">用patch将rar相关代码全部移除</a>了。</p><blockquote><p>Fedora package note: non-Free unrar code have been removed from the sources (#190277)</p></blockquote><p>7z的作者Igor Pavlov也针对这个回复了一些有疑问的人。 Igor Pavlov ( <a href="https://sourceforge.net/p/sevenzip/discussion/45798/thread/dc2d0438/#8f9f">sourceforge.net/p/sevenzip/discussion/45798/thread/dc2d0438/#8f9f</a> ):</p><blockquote><p>fedora/centos have removed 7-zip&#x27;s unrar code as non-free code. Maybe you can use p7zip compiled for another linux systems with 7-zip&#x27;s unrar plugin: p7zip-full and p7zip-rar</p><p>RAR code is divided into two parts in p7zip:</p><ol><li>free part of unrar (in p7zip-full)</li><li>non-free part of unrar (p7zip-rar)</li></ol><p>But <strong>fedora have removed both parts of unrar code</strong>.</p></blockquote><p>等于是别人家的7z命令都能解压rar,你Fedora家的不能。为此老灯专门写了一个<a href="https://github.com/ttys3/fedora-rpm-p7zip">rpm spec</a>用于构建完整功能版的p7zip</p></li><li><p>不是开箱即用,对新手极略不友好:比如最基本的需求,安装Nvidia或AMD显卡驱动,或者Intel GPU vaapi 支持驱动,你得从一个叫<a href="https://rpmfusion.org/">rpmfusion</a>的第三方仓库安装。</p><blockquote><p>RPM Fusion项目是社区维护的软件存储库,提供了由于法律原因无法在Fedora中分发的其他软件包。 软件专利适用于RPM Fusion中的某些软件包,因此,在某些国家/地区安装这些软件包可能不合法:例如,在美国或日本。</p><p>RPM Fusion还提供用于Red Hat Enterprise Linux的软件包</p><p><a href="https://docs.fedoraproject.org/en-US/quick-docs/setup_rpmfusion/#con_the-purpose-of-rpm-fusion_enabling-the-rpmfusion-repositories">https://docs.fedoraproject.org/en-US/quick-docs/setup_rpmfusion/#con_the-purpose-of-rpm-fusion_enabling-the-rpmfusion-repositories</a></p></blockquote></li><li><p>有些常见的包名没有采用通用名字,比如nodejs包管理工具yarn, 在Fedora里叫<a href="https://src.fedoraproject.org/rpms/yarnpkg">yarnpkg</a></p></li><li><p>Fedora的文档不是很多(尽管如此,它的文档依旧比Ubuntu的要好),虽然RHEL 的文档非常全面,但是基本上那些是跟Server相关的。一旦你要查找桌面环境相关的问题,你会发现Fedora的文档少得可怜。文档这方面ArchLinux可能是做得最好的(没有之一)。</p></li></ol><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://fedoramagazine.org/">https://fedoramagazine.org/</a></p><p><a href="https://git.archlinux.org/pacman.git/commit/?id=c0e9be7973be6c81b22fde91516fb8991e7bb07b">Remove support for deltas from libalpm</a></p><p><a href="https://www.reddit.com/r/archlinux/comments/b7zkg5/why_delta_support_removed_from_pacman/">https://www.reddit.com/r/archlinux/comments/b7zkg5/why_delta_support_removed_from_pacman/</a></p><p><a href="https://fedoraproject.org/wiki/Fedora_Release_Life_Cycle#Development_Schedule">https://fedoraproject.org/wiki/Fedora_Release_Life_Cycle#Development_Schedule</a></p><p><a href="https://en.wikipedia.org/wiki/List_of_Linux_distributions#Fedora-based">https://en.wikipedia.org/wiki/List_of_Linux_distributions#Fedora-based</a></p><p><a href="https://spins.fedoraproject.org/">https://spins.fedoraproject.org/</a></p><p><a href="https://ttys3.dev/post/linux/fedora/fedora31-upgrade-to-fedora32/">https://ttys3.dev/post/linux/fedora/fedora31-upgrade-to-fedora32/</a></p><p><a href="https://ttys3.dev/post/linux/fedora/fedora32-upgrade-to-fedora33/">https://ttys3.dev/post/linux/fedora/fedora32-upgrade-to-fedora33/</a></p><p><a href="https://fedoraproject.org/wiki/Changes/Switch_RPMs_to_zstd_compression">https://fedoraproject.org/wiki/Changes/Switch_RPMs_to_zstd_compression</a></p><p><a href="https://fedoraproject.org/wiki/Changes/BtrfsByDefault">https://fedoraproject.org/wiki/Changes/BtrfsByDefault</a></p><p><a href="https://fedoraproject.org/wiki/Changes/BtrfsTransparentCompression">https://fedoraproject.org/wiki/Changes/BtrfsTransparentCompression</a></p><p><a href="https://fedoraproject.org/wiki/Changes">https://fedoraproject.org/wiki/Changes</a></p><p><a href="https://docs.fedoraproject.org/en-US/quick-docs/setup_rpmfusion/">https://docs.fedoraproject.org/en-US/quick-docs/setup_rpmfusion/</a></p><p><a href="https://codeghar.wordpress.com/2012/09/26/fedora-the-good-the-bad-and-the-ugly/">https://codeghar.wordpress.com/2012/09/26/fedora-the-good-the-bad-and-the-ugly/</a> (很古老的文章,有一定的参考意义,但是其中很多问题已经不存在了)</p><p><a href="https://en.wikipedia.org/wiki/Anaconda_(installer)">https://en.wikipedia.org/wiki/Anaconda_(installer)</a></p><p><a href="https://fedoraproject.org/wiki/Licensing:Main#Good_Licenses">https://fedoraproject.org/wiki/Licensing:Main#Good_Licenses</a></p><p><a href="https://fedoraproject.org/wiki/Licensing:FAQ">https://fedoraproject.org/wiki/Licensing:FAQ</a></p><p><a href="https://fedoraproject.org/wiki/Third_party_repositories">https://fedoraproject.org/wiki/Third_party_repositories</a></p> Fri, 05 Mar 2021 14:27:14 GMT ttyS3 fedoralinux https://ttys3.dev/blog/rename-hugo-blog-git-repo-branch-from-master-to-main Rename Hugo Blog Git Repo Branch From master To main https://ttys3.dev/blog/rename-hugo-blog-git-repo-branch-from-master-to-main <p>最近编译了最新版的Git, 发现init repo的时候会提示配置全局默认branch (这事儿都是由black lives matter运动搞起的)。好吧,既然能少打一个字符,就改成 <code>main</code> 吧。</p><h2 id="切换-git-分支为-main"><a aria-hidden="true" href="#切换-git-分支为-main" tabindex="-1"><span class="icon icon-link"></span></a>切换 Git 分支为 main</h2><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">git</span> checkout master </span><span class="code-line"> </span><span class="code-line"><span class="token function">git</span> branch <span class="token parameter variable">-m</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 删除本地分支</span> </span><span class="code-line"><span class="token function">git</span> branch <span class="token parameter variable">-d</span> master </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 删除远程分支</span> </span><span class="code-line"><span class="token function">git</span> push origin <span class="token parameter variable">--delete</span> master </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># (并不是真正想push, 只是隐式地将远程分支设置为了跟踪main)</span> </span><span class="code-line"><span class="token function">git</span> push origin <span class="token parameter variable">-u</span> main </span></code></pre></div><h2 id="github-配置"><a aria-hidden="true" href="#github-配置" tabindex="-1"><span class="icon icon-link"></span></a>Github 配置</h2><p>在 Github repo 设置 -&gt; <strong>Branches</strong> 里, 将默认分支设置为 <code>main</code></p><div><img alt="" src="https://ttys3.dev/static/assets/github-set-dft-branch-to-main-BO67VESD.png" width="1560" height="581"/></div><h2 id="netlify-配置"><a aria-hidden="true" href="#netlify-配置" tabindex="-1"><span class="icon icon-link"></span></a>Netlify 配置</h2><p>老灯还使用了netlify 和 netlify cms, 因此这两个的分支都要配置</p><p>Netlify Build 设置里将默认分支设置成 <code>main</code></p><div><img alt="" src="https://ttys3.dev/static/assets/netlify-set-build-branch-2TCYUH4Z.png" width="2080" height="945"/></div><p>Netlify CMS admin/<code>config.yml</code> 默认分支设置成 <code>main</code> , 如果这里忘记设置了,你将无法登录 Netlify CMS 后台。</p><div class="relative"><pre><code class="code-highlight language-yaml"><span class="code-line"><span class="token atrule key">backend</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">name</span><span class="token punctuation">:</span> git<span class="token punctuation">-</span>gateway </span><span class="code-line"> <span class="token atrule key">branch</span><span class="token punctuation">:</span> main <span class="token comment"># Branch to update (optional; defaults to master)</span> </span><span class="code-line"> <span class="token atrule key">squash_merges</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token comment"># beta feature</span> </span></code></pre></div><p>会有如下错误:</p><blockquote><p>Git Gateway Error: Please ask your site administrator to reissue the Git Gateway token.</p></blockquote><p>如果你打开浏览器调试工具,你会发现它还在向 master 发送 token,这肯定是不行的。因此要修正。</p><p>另外,如果还是登录不进行,清除一下 Netlify CMS admin 的 cookies 信息 和 local storage.</p> Fri, 05 Mar 2021 06:34:37 GMT ttyS3 git https://ttys3.dev/blog/recompile-git-with-openssl-under-ubuntu 坑爹 -- Ubuntu 版的 Git 使用的 GnuTLS 而不是 OpenSSL 提供的 TLS 实现 https://ttys3.dev/blog/recompile-git-with-openssl-under-ubuntu <h2 id="起因"><a href="#起因" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>起因</h2><p>为什么用的是Ubuntu? 老灯你不是喜欢ArchLinux的么? 没错,这个Ubuntu只是老灯在工作环境使用的, 主要是团队要求。与大家保持一致。</p><p>当前我的neovim还是用的<a href="https://github.com/junegunn/vim-plug">Vim Plug</a>这个插件管理器(已经在着手准备迁移到init.lua + packer.nvim 了)。 在更新neovim 插件时(<code>:PlugUpdate</code> ) 遇到了以下错误:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">x vim-startify: </span><span class="code-line"> fatal: unable to access <span class="token string">&#x27;https://github.com/mhinz/vim-startify.git/&#x27;</span><span class="token builtin class-name">:</span> gnutls_handshake<span class="token punctuation">(</span><span class="token punctuation">)</span> failed: The TLS connection was non-properly terminated. </span></code></pre></div><p><code>gnutls_handshake() failed</code> 非常吸睛,因为我之前在Arch和 Fedora 上使用Git 都从来不会遇到这个错误的。</p><p>再跑了下更新命令,抓取到了真正命令:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">/usr/lib/git-core/git-remote-https origin https://github.com/mhinz/vim-startify.git </span></code></pre></div><p>看来Ubuntu版的git-remote-https用的GnuTLS, 然后验证一下,果然中招了:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ ldd /usr/lib/git-core/git-remote-https <span class="token operator">|</span> <span class="token function">grep</span> <span class="token function">curl</span> </span><span class="code-line"> libcurl-gnutls.so.4 <span class="token operator">=</span><span class="token operator">&gt;</span> /lib/x86_64-linux-gnu/libcurl-gnutls.so.4 <span class="token punctuation">(</span>0x00007fc39a56b000<span class="token punctuation">)</span> </span></code></pre></div><h2 id="编译启用-openssl-支持的-git"><a href="#编译启用-openssl-支持的-git" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>编译启用 openssl 支持的 Git</h2><p>当然了,这种事情,老灯不可能是第一个发现的,gist里有无数“修复”这个问题的shell脚本。 Github上也有。老灯找到一个不错了: <a href="https://github.com/paul-nelson-baker/git-openssl-shellscript">https://github.com/paul-nelson-baker/git-openssl-shellscript</a> fork 之,增加了多线程下载支持和多核心编译支持。毕竟,要速度嘛。</p><p>老灯的仓库在这: <a href="https://github.com/ttys3/git-openssl-shellscript">https://github.com/ttys3/git-openssl-shellscript</a></p><p>这个脚本会卸载Ubuntu自带的git (同时也会卸载git-flow), 在此之前我们先记录下原版git的样子吧:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">git</span> <span class="token parameter variable">--version</span> </span><span class="code-line"><span class="token function">git</span> version <span class="token number">2.27</span>.0 </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">sudo</span> <span class="token function">apt</span> info <span class="token function">git</span> </span><span class="code-line">Package: <span class="token function">git</span> </span><span class="code-line">Version: <span class="token number">1</span>:2.27.0-1ubuntu1 </span><span class="code-line">Priority: optional </span><span class="code-line">Section: vcs </span><span class="code-line">Origin: Ubuntu </span><span class="code-line">Maintainer: Ubuntu Developers <span class="token operator">&lt;</span>[email protected]<span class="token operator">&gt;</span> </span><span class="code-line">Original-Maintainer: Jonathan Nieder <span class="token operator">&lt;</span>[email protected]<span class="token operator">&gt;</span> </span><span class="code-line">Bugs: https://bugs.launchpad.net/ubuntu/+filebug </span><span class="code-line">Installed-Size: <span class="token number">39.2</span> MB </span><span class="code-line">Provides: git-completion, git-core </span><span class="code-line">Depends: libc6 <span class="token punctuation">(</span><span class="token operator">&gt;=</span> <span class="token number">2.28</span><span class="token punctuation">)</span>, libcurl3-gnutls <span class="token punctuation">(</span><span class="token operator">&gt;=</span> <span class="token number">7.56</span>.1<span class="token punctuation">)</span>, libexpat1 <span class="token punctuation">(</span><span class="token operator">&gt;=</span> <span class="token number">2.0</span>.1<span class="token punctuation">)</span>, libpcre2-8-0 <span class="token punctuation">(</span><span class="token operator">&gt;=</span> <span class="token number">10.22</span><span class="token punctuation">)</span>, zlib1g <span class="token punctuation">(</span><span class="token operator">&gt;=</span> <span class="token number">1</span>:1.2.0<span class="token punctuation">)</span>, perl, liberror-perl, git-man <span class="token punctuation">(</span><span class="token operator">&gt;&gt;</span> <span class="token number">1</span>:2.27.0<span class="token punctuation">)</span>, git-man <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">1</span>:2.27.0-.<span class="token punctuation">)</span> </span><span class="code-line">Recommends: ca-certificates, patch, less, ssh-client </span><span class="code-line">Suggests: gettext-base, git-daemon-run <span class="token operator">|</span> git-daemon-sysvinit, git-doc, git-el, git-email, git-gui, gitk, gitweb, git-cvs, git-mediawiki, git-svn </span><span class="code-line">Breaks: bash-completion <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">1</span>:1.90-1<span class="token punctuation">)</span>, cogito <span class="token punctuation">(</span><span class="token operator">&lt;=</span> <span class="token number">0.18</span>.2+<span class="token punctuation">)</span>, dgit <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">5.1</span>~<span class="token punctuation">)</span>, git-buildpackage <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">0.6</span>.5<span class="token punctuation">)</span>, git-core <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">1</span>:1.7.0.4-1.<span class="token punctuation">)</span>, gitosis <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">0.2</span>+20090917-7<span class="token punctuation">)</span>, gitpkg <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">0.15</span><span class="token punctuation">)</span>, gitweb <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">1</span>:1.7.4~rc1<span class="token punctuation">)</span>, guilt <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">0.33</span><span class="token punctuation">)</span>, openssh-client <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">1</span>:6.8<span class="token punctuation">)</span>, stgit <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">0.15</span><span class="token punctuation">)</span>, stgit-contrib <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">0.15</span><span class="token punctuation">)</span> </span><span class="code-line">Replaces: git-core <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">1</span>:1.7.0.4-1.<span class="token punctuation">)</span>, gitweb <span class="token punctuation">(</span><span class="token operator">&lt;&lt;</span> <span class="token number">1</span>:1.7.4~rc1<span class="token punctuation">)</span> </span><span class="code-line">Homepage: https://git-scm.com/ </span></code></pre></div><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">git</span> clone https://github.com/ttys3/git-openssl-shellscript.git </span><span class="code-line"><span class="token builtin class-name">cd</span> git-openssl-shellscript </span><span class="code-line"> </span><span class="code-line">./compile-git-with-openssl.sh --skip-tests </span></code></pre></div><p>编译安装完,检查下:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">git</span> <span class="token parameter variable">--version</span> </span><span class="code-line"><span class="token function">git</span> version <span class="token number">2.31</span>.0-rc1 </span></code></pre></div><p>没找到<code>git-remote-https</code> 在哪,随便clone个大仓库(为我们ps | grep 争取时间),然后找出来路径。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 并不是真正要clone内核源码。。。</span> </span><span class="code-line">❯git clone https://github.com/torvalds/linux.git </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 新开另一个tab找路径</span> </span><span class="code-line">❯ <span class="token function">ps</span> aux <span class="token operator">|</span> <span class="token function">grep</span> <span class="token string">&#x27;torvalds/linux&#x27;</span> </span><span class="code-line">ttys3 <span class="token number">2887728</span> <span class="token number">0.0</span> <span class="token number">0.0</span> <span class="token number">15060</span> <span class="token number">3964</span> pts/18 S+ <span class="token number">16</span>:17 <span class="token number">0</span>:00 /usr/libexec/git-core/git remote-https origin https://github.com/torvalds/linux.git </span><span class="code-line">ttys3 <span class="token number">2887729</span> <span class="token number">4.0</span> <span class="token number">0.0</span> <span class="token number">108636</span> <span class="token number">14272</span> pts/18 R+ <span class="token number">16</span>:17 <span class="token number">0</span>:00 /usr/libexec/git-core/git-remote-https origin https://github.com/torvalds/linux.git </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 找到了,看看</span> </span><span class="code-line">❯ ldd /usr/libexec/git-core/git-remote-https <span class="token operator">|</span> <span class="token function">grep</span> libcurl </span><span class="code-line"> libcurl.so.4 <span class="token operator">=</span><span class="token operator">&gt;</span> /lib/x86_64-linux-gnu/libcurl.so.4 <span class="token punctuation">(</span>0x00007ff2e529d000<span class="token punctuation">)</span> </span><span class="code-line"> </span></code></pre></div><p>这次我们依赖的是<code>libcurl4-openssl-dev</code> (而不是<code>libcurl4-gnutls-dev</code>)</p><p>❯ dpkg -L libcurl4-openssl-dev ... /usr/lib/x86_64-linux-gnu/libcurl.so ...</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"> </span><span class="code-line">## troubleshoot </span><span class="code-line"> </span><span class="code-line">编译的时候,由于要查找原包的依赖,因此需要启动apt仓库的 <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">deb-src</span><span class="token string template-punctuation">`</span></span> 源。 </span><span class="code-line"> </span><span class="code-line">ensure you have <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">deb-src</span><span class="token string template-punctuation">`</span></span> enabled <span class="token keyword">in</span> <span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string">/etc/apt/sources.list</span><span class="token string template-punctuation">`</span></span> </span><span class="code-line"> </span><span class="code-line">以下是老灯的配置(Ubuntu <span class="token number">20.10</span><span class="token punctuation">)</span><span class="token operator">:</span> </span><span class="code-line"> </span><span class="code-line"><span class="token template-string"><span class="token string template-punctuation">`</span><span class="token string template-punctuation">`</span></span>`shell </span><span class="code-line">❯ cat <span class="token operator">/</span>etc<span class="token operator">/</span>apt<span class="token operator">/</span>sources<span class="token punctuation">.</span><span class="token property-access">list</span> <span class="token operator">|</span> grep <span class="token operator">-</span>v <span class="token string">&#x27;#&#x27;</span> </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy main restricted </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy main restricted </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>updates main restricted </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>updates main restricted </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy universe </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy universe </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>updates universe </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>updates universe </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy multiverse </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy multiverse </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>updates multiverse </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>updates multiverse </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>backports main restricted universe multiverse </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>backports main restricted universe multiverse </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>security main restricted </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>security main restricted </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>security universe </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>security universe </span><span class="code-line"> </span><span class="code-line">deb https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>security multiverse </span><span class="code-line">deb<span class="token operator">-</span>src https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>ubuntu groovy<span class="token operator">-</span>security multiverse </span></code></pre></div><p>新版本的Git 提升将默认的<code>master</code> 分支修改为 <code>main</code> (美国黑人运动的结果,影响无处不在啊,据说Mysql也要把主从同步里的相关术语里的master和slave改掉呢)</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">❯ <span class="token function">git</span> init <span class="token builtin class-name">.</span> </span><span class="code-line">hint: Using <span class="token string">&#x27;master&#x27;</span> as the name <span class="token keyword">for</span> the initial branch. This default branch name </span><span class="code-line">hint: is subject to change. To configure the initial branch name to use <span class="token keyword">in</span> all </span><span class="code-line">hint: of your new repositories, <span class="token function">which</span> will suppress this warning, call: </span><span class="code-line">hint: </span><span class="code-line">hint: <span class="token function">git</span> config <span class="token parameter variable">--global</span> init.defaultBranch <span class="token operator">&lt;</span>name<span class="token operator">&gt;</span> </span><span class="code-line">hint: </span><span class="code-line">hint: Names commonly chosen instead of <span class="token string">&#x27;master&#x27;</span> are <span class="token string">&#x27;main&#x27;</span>, <span class="token string">&#x27;trunk&#x27;</span> and </span><span class="code-line">hint: <span class="token string">&#x27;development&#x27;</span><span class="token builtin class-name">.</span> The just-created branch can be renamed via this command: </span><span class="code-line">hint: </span><span class="code-line">hint: <span class="token function">git</span> branch <span class="token parameter variable">-m</span> <span class="token operator">&lt;</span>name<span class="token operator">&gt;</span> </span></code></pre></div><p>得,那就配置一下吧, <code>git config --global init.defaultBranch main</code></p><p><code>main</code> 还能少打一个字节。</p> Wed, 03 Mar 2021 13:07:39 GMT ttyS3 ubuntugitgnutlstlsopenssl https://ttys3.dev/blog/chromium-google-account-sync-features-will-stop-working-on-march-15 Time to say goodbye -- Chromium Google账号同步功能将于3月15日停止工作 https://ttys3.dev/blog/chromium-google-account-sync-features-will-stop-working-on-march-15 <p>这个消息其实很早Google就放出了。</p><p>早在1月25号左右,Fedora打包的Chromium就已经移除了账号同步功能。</p><p><a href="https://www.theregister.com/2021/01/25/use_firefox_fedora_chromium_maintainer/">Fedora&#x27;s Chromium maintainer suggests switching to Firefox as Google yanks features in favour of Chrome</a></p><blockquote><p>&#x27;They&#x27;re not closing a security hole, they&#x27;re just requiring that everyone use Chrome&#x27;</p></blockquote><div><img alt="" src="https://ttys3.dev/static/assets/chromium-google-account-sync-btn-removed-EYOMR2YP.png" width="671" height="743"/></div><p><strong>FEDORA-2021-48866282e5 created by spot for Fedora 33</strong></p><blockquote><p>This is probably not the update you want.</p><p>Let me be clear, it does fix the security vulnerabilities in this list:</p><p>CVE-2020-16044 CVE-2021-21118 CVE-2021-21119 CVE-2021-21120 CVE-2021-21121 CVE-2021-21122 CVE-2021-21123 CVE-2021-21124 CVE-2021-21125 CVE-2021-21126 CVE-2021-21127 CVE-2021-21129 CVE-2021-21130 CVE-2021-21131 CVE-2021-21132 CVE-2021-21133 CVE-2021-21134 CVE-2021-21135 CVE-2021-21136 CVE-2021-21137 CVE-2021-21138 CVE-2021-21139 CVE-2021-21140 CVE-2021-21141 CVE-2021-21117 CVE-2021-21128</p><p>But it will not behave like Google Chrome does.</p><p>Google has announced that it is cutting off access to the Sync and &quot;other Google Exclusive&quot; APIs from all builds except Google Chrome. This will make the Fedora Chromium build significantly less functional (along with every other distro packaged Chromium). It is noteworthy that Google gave the builders of distribution Chromium packages these access rights back in 2013 via API keys, specifically so that we could have open source builds of Chromium with (near) feature parity to Chrome. And now they&#x27;re taking it away. The reasoning given for this change? Google does not want users to be able to &quot;access their personal Chrome Sync data (such as bookmarks) ... with a non-Google, Chromium-based browser.&quot; They&#x27;re not closing a security hole, they&#x27;re just requiring that everyone use Chrome.</p><p>Or to put it bluntly, they do not want you to access their Google API functionality without using proprietary software (Google Chrome). There is no good reason for Google to do this, other than to force people to use Chrome.</p><p>I gave a lot of thought to whether I wanted to continue to maintain the Chromium package in Fedora, given that many (most?) users will be confused/annoyed when API functionality like sync and geolocation stops working for no good reason. Ultimately, I decided to continue for now, because there were at least some users who didn&#x27;t mind, and if I stopped, someone else would start over and run blindly into this problem.</p><p>I would say that you might want to reconsider whether you want to use Chromium or not. If you want the full &quot;Google&quot; experience, you can run the proprietary Chrome. If you want to use a FOSS browser that isn&#x27;t hobbled, there is a Firefox package in Fedora.</p><p>Oh, last, but not least, Google isn&#x27;t shutting off the API access until March 15, 2021, but I have gone ahead and disabled it starting with this update. I&#x27;d rather you read about it here (even though most users will never see this) than have it just happen.</p></blockquote><p>根据 <a href="https://www.omgubuntu.co.uk/2021/01/chromium-sync-google-api-removed">omg!ubuntu 的文章</a>,主要被砍掉的功能包括:</p><ul><li><strong>Google account sync</strong></li><li><strong>Geolocation</strong></li><li><strong>Click to Call</strong></li><li><strong>Chrome spelling API</strong></li><li><strong>Contacts API</strong></li><li><strong>Chrome translate element</strong></li></ul><h2 id="不用chromium选哪个"><a href="#不用chromium选哪个" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>不用Chromium,选哪个?</h2><h3 id="mozilla-firefox"><a href="#mozilla-firefox" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Mozilla Firefox</h3><p>开源产品里面,好像基本上没太多选择,大家一致推荐Mozilla Firefox.</p><p>老灯用Mozilla Firefox也比较多,但是,最近反而是这个Chromium浏览器事件,使得我重新思考, 是不是要弃Firefox而转用其它了。</p><p>这么多年了,Firefox的渲染和网页打开速度还是PK不过Chrome(或Chromium系). 我4K 浏览器,每天打开Firefox 都要按 F11 最大化 Firefox, 然后再切回正常大小。而我这波操作完全只是为了让Firefox恢复正常的窗体大小,这么多年了,Firefox这点事都做不好。 还有一个一直存在的“background-color 样式在 Linux 下不工作”的问题,见<a href="/post/frontend/basis/why-firefox-option-background-color-do-not-work-under-linux/">我之前的文章</a></p><p>不过Firefox也有很多地方做得不错的,比如浏览器项目一直坚做持下来了,还搞出来个Rust语言。</p><p>还有 Firefox开发者版 开箱即用,对开发者比较友好。自带的 lockwise app (iOS/Android) 可以自动同步Firefox记录的密码,相当于一个比较简陋版的 1Password 之类的app了。lockwise 能够满足基本需求,我也用了蛮久的。</p><h3 id="chrome"><a href="#chrome" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Chrome</h3><p>习惯了Google系的,可以选择用闭源的 Chrome.</p><p>除了stable版,这个repo还有 google-chrome-beta 和 google-chrome-unstable</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># Fedora 33</span> </span><span class="code-line">dnf <span class="token function">install</span> fedora-workstation-repositories </span><span class="code-line">dnf config-manager --set-enabled google-chrome </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> google-chrome-stable </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># CentOS/RHEL 8.2/7.8</span> </span><span class="code-line"><span class="token function">cat</span> <span class="token operator">&lt;&lt;</span> <span class="token string">EOF<span class="token bash punctuation"> <span class="token operator">&gt;</span> /etc/yum.repos.d/google-chrome.repo</span> </span></span><span class="code-line"><span class="token string">[google-chrome] </span></span><span class="code-line"><span class="token string">name=google-chrome </span></span><span class="code-line"><span class="token string">baseurl=http://dl.google.com/linux/chrome/rpm/stable/x86_64 </span></span><span class="code-line"><span class="token string">enabled=1 </span></span><span class="code-line"><span class="token string">gpgcheck=1 </span></span><span class="code-line"><span class="token string">gpgkey=https://dl.google.com/linux/linux_signing_key.pub </span></span><span class="code-line"><span class="token string">EOF</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Ubuntu</span> </span><span class="code-line"><span class="token function">wget</span> <span class="token parameter variable">-q</span> <span class="token parameter variable">-O</span> - https://dl-ssl.google.com/linux/linux_signing_key.pub <span class="token operator">|</span> <span class="token function">sudo</span> apt-key <span class="token function">add</span> - </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">sh</span> <span class="token parameter variable">-c</span> <span class="token string">&#x27;echo &quot;deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main&quot; &gt;&gt; /etc/apt/sources.list.d/google.list&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> update </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> google-chrome-stable </span></code></pre></div><h3 id="microsoft-edge"><a href="#microsoft-edge" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Microsoft Edge</h3><p>喜欢巨硬全家桶的,可以选 <a href="https://www.microsoftedgeinsider.com/en-us/download/">Microsoft Edge</a> , 老灯在Fedora 33 上安装了 Edge Linux 开发预览版,目前来说体验一般,打开页面速度也不快。另外,账号同步功能也还不可用。等吧。</p><div><img alt="" src="https://ttys3.dev/static/assets/ms-edge-linux-acc-sync-not-avai-5NPPX4DI.png" width="1726" height="687"/></div><p>安装:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># Fedora</span> </span><span class="code-line"><span class="token comment">## Setup</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">rpm</span> <span class="token parameter variable">--import</span> https://packages.microsoft.com/keys/microsoft.asc </span><span class="code-line"><span class="token function">sudo</span> dnf config-manager --add-repo https://packages.microsoft.com/yumrepos/edge </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">mv</span> /etc/yum.repos.d/packages.microsoft.com_yumrepos_edge.repo /etc/yum.repos.d/microsoft-edge-dev.repo </span><span class="code-line"><span class="token comment">## Install</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> microsoft-edge-dev </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Debian/Ubuntu</span> </span><span class="code-line"><span class="token comment">## Setup</span> </span><span class="code-line"><span class="token function">curl</span> https://packages.microsoft.com/keys/microsoft.asc <span class="token operator">|</span> gpg <span class="token parameter variable">--dearmor</span> <span class="token operator">&gt;</span> microsoft.gpg </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">install</span> <span class="token parameter variable">-o</span> root <span class="token parameter variable">-g</span> root <span class="token parameter variable">-m</span> <span class="token number">644</span> microsoft.gpg /etc/apt/trusted.gpg.d/ </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">sh</span> <span class="token parameter variable">-c</span> <span class="token string">&#x27;echo &quot;deb [arch=amd64] https://packages.microsoft.com/repos/edge stable main&quot; &gt; /etc/apt/sources.list.d/microsoft-edge-dev.list&#x27;</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">rm</span> microsoft.gpg </span><span class="code-line"><span class="token comment">## Install</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt</span> update </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> microsoft-edge-dev </span></code></pre></div><h3 id="vivaldi"><a href="#vivaldi" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Vivaldi</h3><p>这个是啥?根据ArchLinux的wiki:</p><blockquote><p><a href="http://vivaldi.com/">Vivaldi</a> is a new web browser from former <a href="https://wiki.archlinux.org/index.php/Opera" title="Opera">Opera</a> founder &amp; team members, based on <a href="https://wiki.archlinux.org/index.php/Chromium" title="Chromium">Chromium</a> and focused on personalization aspects.</p></blockquote><p><a href="https://vivaldi.com/zh-hans/">Vivaldi</a> 自带广告过滤器+鼠标手势。tab和窗体背景能自动根据网页主色调变色。侧边栏。</p><p>主打隐私?(这个嘛,官方宣称zero tracking)。能安装Google Chrome插件。</p><p>官方没有提供 Arch 包,好在<a href="https://archlinux.org/packages/community/x86_64/vivaldi/">有热心的社区贡献者</a></p><p>官网:看看大众对 VIVALDI 的评价</p><blockquote><p>对Vivaldi最新版本的第一印象 - 它比Firefox更快。-- Barry Collins <a href="https://twitter.com/bazzacollins/status/993760736420777984">via twitter</a></p></blockquote><p>我看了有点想笑,哈哈哈哈哈哈哈哈</p><p>这么多年了,Firefox 还是这么慢。</p><blockquote><p>it&#x27;s faster than Firefox.</p><blockquote><p>it&#x27;s faster than Firefox.</p><blockquote><p>it&#x27;s faster than Firefox.</p><blockquote><p>it&#x27;s faster than Firefox.</p></blockquote></blockquote></blockquote></blockquote><p><a href="https://help.vivaldi.com/desktop/install-update/manual-setup-vivaldi-linux-repositories/">安装指导 -&gt;</a></p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># DNF (Fedora)</span> </span><span class="code-line"><span class="token function">sudo</span> dnf config-manager --add-repo https://repo.vivaldi.com/archive/vivaldi-fedora.repo </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> vivaldi-stable </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># APT (Utuntu/Debian)</span> </span><span class="code-line"><span class="token comment"># apt-key is deprecated</span> </span><span class="code-line"><span class="token function">curl</span> https://repo.vivaldi.com/archive/linux_signing_key.pub <span class="token operator">|</span> gpg <span class="token parameter variable">--dearmor</span> <span class="token operator">&gt;</span> vivaldi.gpg </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">install</span> <span class="token parameter variable">-o</span> root <span class="token parameter variable">-g</span> root <span class="token parameter variable">-m</span> <span class="token number">644</span> vivaldi.gpg /etc/apt/trusted.gpg.d/ </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">rm</span> vivaldi.gpg </span><span class="code-line"><span class="token function">sudo</span> add-apt-repository <span class="token string">&#x27;deb https://repo.vivaldi.com/archive/deb/ stable main&#x27;</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt</span> update <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> vivaldi-stable </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># H.264 and AAC support</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> chromium-codecs-ffmpeg-extra </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Pacman see https://wiki.archlinux.org/index.php/Vivaldi</span> </span><span class="code-line"><span class="token comment"># for media codec installation guide</span> </span><span class="code-line"><span class="token function">sudo</span> pacman <span class="token parameter variable">-S</span> vivaldi </span></code></pre></div><p>我要吐槽一下,Vivaldi repo 那个服务器是真的慢。。。基本上64KB/s的下载速度。</p><p><a href="https://vivaldi.com/blog/troubleshoot-common-problems-vivaldi/">https://vivaldi.com/blog/troubleshoot-common-problems-vivaldi/</a></p><p><a href="https://vivaldi.com/blog/browse-fast-with-mouse-gestures/">https://vivaldi.com/blog/browse-fast-with-mouse-gestures/</a></p><p><a href="https://vivaldi.com/blog/vivaldi-browser-open-source/">https://vivaldi.com/blog/vivaldi-browser-open-source/</a></p><p>Vivaldi 老灯试用了两天,有发现一些奇怪的问题,比如有些页面打不开或很慢(跟Firefox一样),但是换成Chrome就能打开或者打开很快。另外,在有些情况下,多打开一些页面会导致 Vivaldi 吃到 100% 的 CPU 从而导致Vivaldi浏览器自身假死或非常卡。</p><p>默认不支持H264和 AAC 解压,需要额外安装包,见 <a href="https://gist.github.com/BlackIkeEagle/5c00face3c7a0f98847a">https://gist.github.com/BlackIkeEagle/5c00face3c7a0f98847a</a></p><p>或 <a href="https://gist.github.com/cega/258ca210e4cd3f02cdca5b721b9045ba">https://gist.github.com/cega/258ca210e4cd3f02cdca5b721b9045ba</a></p><p>安装完记得打开<a href="https://help.vivaldi.com/desktop/media/html5-proprietary-media-on-linux/"></a> <a href="https://www.quirksmode.org/html5/tests/video.html"></a><a href="https://help.vivaldi.com/desktop/media/html5-proprietary-media-on-linux/">https://help.vivaldi.com/desktop/media/html5-proprietary-media-on-linux/</a> 测试一下 H.264 (video) and AAC (audio)支持。</p><p>这个页面有更多的测试面: <a href="https://html5test.com/index.html">https://html5test.com/index.html</a></p><p>更多资料可参考 <a href="https://gist.github.com/BlackIkeEagle/5c00face3c7a0f98847a">How to use H.264 support In Vivaldi, via an alternative FFMpeg library</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://www.theregister.com/2021/01/25/use_firefox_fedora_chromium_maintainer/">https://www.theregister.com/2021/01/25/use_firefox_fedora_chromium_maintainer/</a></p><p><a href="https://bodhi.fedoraproject.org/updates/FEDORA-2021-48866282e5">https://bodhi.fedoraproject.org/updates/FEDORA-2021-48866282e5</a></p><p><a href="https://www.omgubuntu.co.uk/2021/01/chromium-sync-google-api-removed">https://www.omgubuntu.co.uk/2021/01/chromium-sync-google-api-removed</a></p><p><a href="https://vivaldi.com/zh-hans/">https://vivaldi.com/zh-hans/</a></p><p><a href="https://help.vivaldi.com/desktop/install-update/manual-setup-vivaldi-linux-repositories/">https://help.vivaldi.com/desktop/install-update/manual-setup-vivaldi-linux-repositories/</a></p><p><a href="https://www.microsoftedgeinsider.com/en-us/download?platform=linux-rpm">https://www.microsoftedgeinsider.com/en-us/download?platform=linux-rpm</a></p><p><a href="https://www.if-not-true-then-false.com/2010/install-google-chrome-with-yum-on-fedora-red-hat-rhel/">https://www.if-not-true-then-false.com/2010/install-google-chrome-with-yum-on-fedora-red-hat-rhel/</a></p><p><a href="https://www.ubuntuupdates.org/ppa/google_chrome">https://www.ubuntuupdates.org/ppa/google_chrome</a></p> Tue, 02 Mar 2021 16:34:06 GMT ttyS3 chromiumgooglegoogle-accountsync https://ttys3.dev/blog/deploy-rust-based-bitwarden-container 部署基于 Rust 的第三方 Bitwarden 服务端容器 https://ttys3.dev/blog/deploy-rust-based-bitwarden-container <h2 id="更新"><a href="#更新" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>更新</h2><p>2021-06-30 更新: 项目名称现在更改为 <a href="https://github.com/dani-garcia/vaultwarden">vaultwarden</a> 了, 详情见 <a href="https://github.com/dani-garcia/vaultwarden/discussions/1642">https://github.com/dani-garcia/vaultwarden/discussions/1642</a></p><h2 id="缘由"><a href="#缘由" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h2><p>1password太贵, 关键是这类软件好像以前还有数据泄露事例。</p><p>在此之前老灯用的是<a href="https://www.mozilla.org/en-US/firefox/lockwise/">Firefox Lockwise</a> , 只能说基本上够用吧。管理密码功能在Firefox上操作。其实就是Firefox本身的功能。 Lockwise app 只是协助在手机端给你自动填充密码。</p><p>这次Google 停止Chromium账号同步功能事件,使得我重新花时间思考了一下,我要切换浏览器的事情。</p><p>这一年多以来,老灯重回Firefox, 刚开始真的很不适应,你们懂的。唯一不适应的就是:慢。打开网页超级慢。</p><p>(因为习惯了Chrome和Chromium的快)</p><p>然而一年过去了,Firefox打开页面的速度并不见得有什么提升。同时有一些在任何其它浏览器都没有的问题,</p><p>在Firefox会出现。fix: (<a href="https://wiki.archlinux.org/index.php/chromium#Native_Wayland_support">native wayland</a>和<a href="https://wiki.archlinux.org/index.php/chromium#Hardware_video_acceleration">硬件加速</a>的支持 已经和 Chromium 一样可以试验性开启了。) , 最明显的可能是 4K 屏下打开Firefox 要按两次 F11 解决窗口大小问题吧(用过的就懂我在说什么)。</p><p>不过,一个Firefox进程打开4000多个tab不会炸机(没错,我真的有四千个tab没关),这一点 Firefox 确实比 吃内存狂魔 Chrome 要好。</p><p>切换掉Firefox 对于我来说,等于要卸载 <a href="https://www.mozilla.org/en-US/firefox/lockwise/">Firefox Lockwise</a> . 因此得找个替代的app.</p><h2 id="为什么是bitwarden"><a href="#为什么是bitwarden" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>为什么是Bitwarden</h2><p>综合考虑之下,选择了 Bitwarden.</p><blockquote><ol><li>全套开源(desktop, mobile, server)</li><li>官方同时提供付费服务(有商业支持,能确保开源项目持续)</li><li>其实官方的 free 版也足够大部分人使用,比如我。</li></ol></blockquote><p>唯一我不太喜欢的可能是,server端是基于C#实现了,同时要mssql 数据库的支持。</p><p>虽然官方有提供docker compose 文件,可以一键 up. 但是对于个人需求来说,为了一个server api, 起一堆的容器,我也不太喜欢。另外,起这么多容器,vps的配置也是要相应的跟得上的。</p><p>不过,翻看博客,找到了一个基于Rust 实现的all in one 的 Bitwarden server:</p><p><a href="https://github.com/dani-garcia/vaultwarden">https://github.com/dani-garcia/vaultwarden</a></p><p>这个版本相对于官方的C#版有什么区别?</p><blockquote><ol><li>除了一些企业版的功能,其它的应该有的都有。可以说对于个人用户是没有影响的。</li><li>小巧啊,all in one 啊,只要跑一个容器。据说只需要10M左右的内存给它跑!</li></ol></blockquote><h2 id="自己构建-bitwarden-容器镜像"><a href="#自己构建-bitwarden-容器镜像" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>自己构建 Bitwarden 容器镜像</h2><p>如果不想使用默认的镜像,可以<a href="https://rs.bitwarden.in/deployment/building-your-own-docker-image">自己构建</a>,很简单。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 构建 docker 镜像:</span> </span><span class="code-line"><span class="token function">docker</span> build <span class="token variable parameter">-t</span> bitwarden_rs <span class="token builtin class-name">.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 要使用 MySQL 后端, 则</span> </span><span class="code-line"><span class="token function">docker</span> build <span class="token variable parameter">-t</span> bitwarden_rs --build-arg <span class="token variable assign-left">DB</span><span class="token operator">=</span>mysql <span class="token builtin class-name">.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 要使用 Postgresql 后端</span> </span><span class="code-line"><span class="token function">docker</span> build <span class="token variable parameter">-t</span> bitwarden_rs --build-arg <span class="token variable assign-left">DB</span><span class="token operator">=</span>postgresql <span class="token builtin class-name">.</span> </span></code></pre></div><p>当然也可以直接用Rust toolchain编译二进制:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 使用所有后端编译(二进制位于 target/release/bitwarden_rs)</span> </span><span class="code-line"><span class="token function">cargo</span> build <span class="token variable parameter">--features</span> sqlite,mysql,postgresql <span class="token variable parameter">--release</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#仅使用 sqlite 编译(二进制位于 target/release/bitwarden_rs)</span> </span><span class="code-line"><span class="token function">cargo</span> build <span class="token variable parameter">--features</span> sqlite <span class="token variable parameter">--release</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 仅使用 mysql 编译(二进制位于 target/release/bitwarden_rs)</span> </span><span class="code-line"><span class="token function">cargo</span> build <span class="token variable parameter">--features</span> mysql <span class="token variable parameter">--release</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 仅使用 postgresql 编译(二进制位于 target/release/bitwarden_rs)</span> </span><span class="code-line"><span class="token function">cargo</span> build <span class="token variable parameter">--features</span> postgresql <span class="token variable parameter">--release</span> </span></code></pre></div><p>构建web ui (web-vault)</p><p>可以直接从 <a href="">dani-garcia/bw_web_builds</a> 下载web-vault的编译版本。</p><p><strong>*注意</strong>:构建密码库需要约 1.5GB 的 RAM。在具有 1GB 或更小容量的 RaspberryPI 之类的系统上,请<a href="">启用交换功能</a>或在功能更强大的计算机上构建,然后从那里将文件复制过来。仅构建时需要大量内存,而运行带密码库的 bitwarden_rs 仅需要***约 10MB** <em>的 RAM。</em></p><p>1、克隆 <a href="">bitwarden/web</a> git 库,并检查最新的发行标签(例如 v2.18.2):</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 克隆库</span> </span><span class="code-line"><span class="token function">git</span> clone https://github.com/bitwarden/web.git web-vault </span><span class="code-line"><span class="token builtin class-name">cd</span> web-vault </span><span class="code-line"><span class="token comment"># 切换到最新的标签</span> </span><span class="code-line"><span class="token function">git</span> checkout <span class="token string">&quot;<span class="token variable"><span class="token variable">$(</span><span class="token function">git</span> tag <span class="token variable parameter">--sort</span><span class="token operator">=</span>v:refname <span class="token operator">|</span> <span class="token function">tail</span> <span class="token variable parameter">-n1</span><span class="token variable">)</span></span>&quot;</span> </span></code></pre></div><p>2、从 <a href="">dani-garcia/bw_web_builds</a> 下载补丁文件并将其复制到 <code>web-vault</code> 文件夹。选择要使用的补丁文件的版本(假设网页密码库版本为 <code>vX.Y.Z</code>):</p><ul><li>如果有版本为 vX.Y.Z 的补丁,则使用该版本</li><li>否则,选择小于 vX.Y.Z 的最大的那一个版本</li></ul><p>3、应用补丁:</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 在&#x27;web-vault&#x27;目录中运行命令</span> </span><span class="code-line"><span class="token function">git</span> apply vX.Y.Z.patch </span></code></pre></div><p>4、然后,构建</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token function">npm</span> <span class="token function">install</span> </span><span class="code-line"><span class="token comment"># Read the note below (we do use this for our docker builds).</span> </span><span class="code-line"><span class="token comment"># 运行 npm audit fix 以修复漏洞。这将自动尝试将软件包升级到较新的版本,</span> </span><span class="code-line"><span class="token comment"># 该版本可能不兼容并破坏web-vault功能。</span> </span><span class="code-line"><span class="token comment"># 如果知道自己在做什么,请自行承担风险。</span> </span><span class="code-line"><span class="token comment"># npm audit fix</span> </span><span class="code-line"><span class="token function">npm</span> run dist </span></code></pre></div><p>5、最后将 <code>build</code> 文件夹的内容复制到目标文件夹中:</p><ul><li>如果与 cargo run --release 一起运行,则目标文件夹为 bitwarden_rs/web-vault。</li><li>如果直接运行已编译的二进制,则它位于二进制旁,为 bitwarden_rs/target/release/web-vault</li></ul><p>老灯构建完已经推到docker hub了:</p><blockquote><p><a href="https://hub.docker.com/r/80x86/vaultwarden">https://hub.docker.com/r/80x86/vaultwarden</a></p></blockquote><h2 id="启动-bitwarden-容器"><a href="#启动-bitwarden-容器" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>启动 Bitwarden 容器</h2><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 删除旧的容器,如果有</span> </span><span class="code-line"><span class="token function">docker</span> stop bitwarden <span class="token operator">&amp;&amp;</span> <span class="token function">docker</span> <span class="token function">rm</span> bitwarden </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 准备数据目录,你也可以存别的地方, vps 没有额外的数据盘的可以直接这样</span> </span><span class="code-line"><span class="token function">mkdir</span> /bw-data/ </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 先拉一下,方便run 顺利执行</span> </span><span class="code-line"><span class="token function">docker</span> pull 80x86/vaultwarden:latest </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 创建并启动容器</span> </span><span class="code-line"><span class="token function">docker</span> run <span class="token variable parameter">-d</span> <span class="token variable parameter">--name</span> bitwarden <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">--restart</span> unless-stopped <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">WEBSOCKET_ENABLED</span><span class="token operator">=</span>true <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">ROCKET_WORKERS</span><span class="token operator">=</span><span class="token number">20</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">SIGNUPS_ALLOWED</span><span class="token operator">=</span>false <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">INVITATIONS_ALLOWED</span><span class="token operator">=</span>false <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-p</span> <span class="token number">3012</span>:3012 <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-p</span> <span class="token number">2052</span>:80 <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-v</span> /bw-data/:/data/ <span class="token punctuation">\</span> </span><span class="code-line">80x86/vaultwarden:latest </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># by the way, rs的是这个</span> </span><span class="code-line"><span class="token comment">#bitwardenrs/server:latest</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 启动后,可以用以下命令观察日志有没有错误 </span> </span><span class="code-line"><span class="token function">docker</span> logs <span class="token variable parameter">-f</span> bitwarden </span></code></pre></div><p>解释: <code>-e SIGNUPS_ALLOWED=false</code> 禁用新用户注册,如果只准备给自己使用,则可以用这个选项禁止其它人注册。注意,容器第一次启动时,请将这个选项设置成 <code>true</code> 开启注册,等你注册完了自己的账号,就可以关闭注册 了。当然,如果你开启了admin后台,也可以通过admin发起邀请注册。</p><p><code>-e INVITATIONS_ALLOWED=false</code> 禁用(普通用户的)邀请权限</p><p>如果机器有开 <code>firewalld</code> 防火墙的,注意开放 <code>443</code> 端口,等会我们要用到。</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line"><span class="token comment"># 防火墙配置</span> </span><span class="code-line">firewall-cmd <span class="token variable parameter">--zone</span><span class="token operator">=</span>public <span class="token variable parameter">--permanent</span> --add-port<span class="token operator">=</span><span class="token number">443</span>/tcp </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 看看现在开放的端口</span> </span><span class="code-line">firewall-cmd <span class="token variable parameter">--zone</span><span class="token operator">=</span>public <span class="token variable parameter">--permanent</span> --list-ports </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 重载配置(注意,如果有其它容器在跑,这个会影响nat转发规则)</span> </span><span class="code-line"><span class="token comment"># 对于podman 可以用 network reload 命令修复 iptables 规则。</span> </span><span class="code-line">firewall-cmd <span class="token variable parameter">--reload</span> </span></code></pre></div><h2 id="nginx反向代理启用https"><a href="#nginx反向代理启用https" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>nginx反向代理+启用https</h2><p>因为 Bitwarden web vault UI 使用的 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API">Web Crypto API</a>,大多数浏览器只有在 HTTPS 环境下才能正常工作。</p><p>(推荐)把 <code>bitwarden_rs</code> 放在一个反向代理后面。比如用<code>nginx</code>来处理 HTTPS 连接</p><p>(不推荐)启用 bitwarden_rs 内置的 HTTPS 功能(通过 Rocket 网络框架)。Rocket 的 HTTPS 实现相对不成熟且有限。此方式也不支持 WebSocket 通知。</p><p>有关这些选项的更多细节,请参考<a href="https://rs.bitwarden.in/deployment/https/enabling-https">启用 HTTPS</a> 部分。</p><p>这里老灯选择最简单的方案:</p><p>nginx反向代理 + <a href="https://www.cloudflare.com/">Cloudflare</a> 代理</p><p><a href="https://www.cloudflare.com/">Cloudflare</a> 里面的tls 配置成 full 模式。然后nginx使用自签名的证书就OK了(cf的 full 模式不会校验 origin server之间的ca 证书, 因此可以放心地用自签名证书)</p><p>由于前置了cf, 真正的证书是cf自动分发的。因此 origin server (也就是我们的nginx反向代理)自签名证书完全不会给浏览器红色警告。</p><p>当然,也可以使用<a href="https://letsencrypt.org/docs/client-options/"> ACME 客户端</a>获取<a href="https://letsencrypt.org/"> Let&#x27;s Encrypt </a>证书。一些反向代理(例如 <a href="https://caddyserver.com/">Caddy</a>)也内置支持使用 ACME 协议获取证书。</p><p>老灯这里用nginx,是因为服务器上已经有nginx在跑了,并且占用了80和443端口。</p><p>如果是全新的服务器,并且80和443没有被占用,我建议使用 Caddy 配置起来 更简单。</p><h2 id="启用-websocket-通知"><a href="#启用-websocket-通知" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>启用 WebSocket 通知</h2><p>要启用 WebSockets 通知,必须使用外部反向代理,并且必须执行以下配置操作:</p><ol><li>将 /notifications/hub 端点路由到 WebSocket 服务器,默认在 3012 端口,确保传递 Connection 和 Upgrade 头。(提示:可以使用 WEBSOCKET_PORT 变量来更改端口)</li><li>将所有其他(包括 /notifications/hub/negotiate)路由到标准 Rocket 服务器,默认在 80 端口上。</li><li>如果使用 Docker,则可能还需要使用 -p 标识来映射两个端口。</li></ol><p>tips: 由于 Rocket (荒野注: 这个server api是基于Rust生态一个叫Rocket的框架开发的) 缺乏对 WebSockets 的支持(尽管<a href="">这是计划的功能</a>),因此要在单独的端口上启动ws服务器。</p><p>当 bitwarden_rs 运行时,默认它会产生 <code>2 * &lt;cpu 核心数&gt;</code> 个 worker 来处理请求。在某些系统上,这可能会由于 worker 数量太少,从而导致性能降低,因此在 docker 镜像中更改为默认产生 10 个线程。可以通过设置<code>ROCKET_WORKERS</code>变量来增加或减少 worker 数量以覆盖此默认设置。</p><p>最后,老灯的配置如下:</p><div class="relative"><pre><code class="code-highlight language-nginx"><span class="code-line"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">listen</span> <span class="token number">443</span> ssl http2</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">server_name</span> 你的域名填写在这里</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment"># Allow large attachments</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">client_max_body_size</span> <span class="token number">128M</span></span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">ssl_certificate</span> ssl/证书文件名.crt</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">ssl_certificate_key</span> ssl/私钥文件名.key</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">limit_conn</span> conn_limit_per_ip <span class="token number">4</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">limit_req</span> zone=req_limit_per_ip burst=4 nodelay</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">limit_rate</span> <span class="token number">256k</span></span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">access_log</span> /var/log/nginx/bw.access.log</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">error_log</span> /var/log/nginx/bw.error.log</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_pass</span> http://127.0.0.1:2052</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_set_header</span> Host <span class="token variable">$host</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Real-IP <span class="token variable">$remote_addr</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Forwarded-For <span class="token variable">$proxy_add_x_forwarded_for</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Forwarded-Proto <span class="token variable">$scheme</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">location</span> /notifications/hub</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_pass</span> http://127.0.0.1:3012</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_set_header</span> Upgrade <span class="token variable">$http_upgrade</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_set_header</span> Connection <span class="token string">&quot;upgrade&quot;</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">location</span> /notifications/hub/negotiate</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">proxy_pass</span> http://127.0.0.1:2052</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h2 id="tls-检测"><a href="#tls-检测" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>TLS 检测</h2><p>TLS 检测工具:</p><p>可以使用 <a href="">https://comodosslstore.com/ssltools/ssl-checker.php</a> 网站来检查 SSL 证书是否包含证书链。缺少证书链,Android 设备将无法连接。</p><p>也可以使用 <a href="">https://www.ssllabs.com/ssltest/analyze.html</a> 网站进行检查,但是它不支持自定义端口。一定要记住选中“Do not show the results on the boards”复选框,不然你的网址就在“Recently Seen”列表中公开暴露了。</p><p>也可以使用 <code>openssl</code> 工具来验证</p><div class="relative"><pre><code class="language-shell code-highlight"><span class="code-line">openssl s_client <span class="token variable parameter">-showcerts</span> <span class="token variable parameter">-connect</span> vault.domain.com:443 </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 或者使用的其他端口,比如 7070</span> </span><span class="code-line">openssl s_client <span class="token variable parameter">-showcerts</span> <span class="token variable parameter">-connect</span> vault.domain.com:7070 </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 输出的开头应类似于以下内容(使用 Let&#x27;s Encrypt 证书):</span> </span><span class="code-line"><span class="token comment"># 有 3 个不同depth(注意,它是从 0 开始的)级别的验证</span> </span><span class="code-line">CONNECTED<span class="token punctuation">(</span>00000003<span class="token punctuation">)</span> </span><span class="code-line"><span class="token variable assign-left">depth</span><span class="token operator">=</span><span class="token number">2</span> O <span class="token operator">=</span> Digital Signature Trust Co., CN <span class="token operator">=</span> DST Root CA X3 </span><span class="code-line">verify return:1 </span><span class="code-line"><span class="token variable assign-left">depth</span><span class="token operator">=</span><span class="token number">1</span> C <span class="token operator">=</span> US, O <span class="token operator">=</span> Let<span class="token string">&#x27;s Encrypt, CN = Let&#x27;</span>s Encrypt Authority X3 </span><span class="code-line">verify return:1 </span><span class="code-line"><span class="token variable assign-left">depth</span><span class="token operator">=</span><span class="token number">0</span> CN <span class="token operator">=</span> vault.domain.com </span><span class="code-line">verify return:1 </span></code></pre></div><h2 id="web-vault-admin界面"><a href="#web-vault-admin界面" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Web Vault Admin界面</h2><p>这里主要是给管理人员用的,对于个人用户单用户来说,就没有必要打开这里了。</p><p>启动管理界面,需要在创建容器时指定环境变量: <code>-e ADMIN_TOKEN=一个超级复杂的密码</code></p><p>有关这些选项的更多细节,请参考<a href="https://rs.bitwarden.in/configuration/enabling-admin-page">启用管理页面</a> 部分。</p><p>这个密码可以直接用命令生成: <code>openssl rand -base64 48</code></p><div><img alt="" src="https://ttys3.dev/static/assets/bw-admin-login-AXMUQHAO.png" width="1368" height="394"/></div><div><img alt="" src="https://ttys3.dev/static/assets/bw-admin-setting-3CVWALK2.png" width="2328" height="1747"/></div><div><img alt="" src="https://ttys3.dev/static/assets/bw-admin-users-ESMBA4JZ.png" width="2371" height="1098"/></div><div><img alt="" src="https://ttys3.dev/static/assets/bw-admin-diagnostis-RXBHOR2O.png" width="2279" height="1618"/></div><p>测试一下禁止注册功能是否正常:</p><div><img alt="" src="https://ttys3.dev/static/assets/bw-test-reg-disabled-feature-YJZRZE5I.png" width="1812" height="1781"/></div><h2 id="用户web-vault界面"><a href="#用户web-vault界面" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>用户Web Vault界面</h2><div><img alt="" src="https://ttys3.dev/static/assets/bw-my-vault-KOVPKCZC.png" width="2095" height="1116"/></div><h2 id="支持上游发展"><a href="#支持上游发展" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>支持上游发展</h2><p>最后,开源不易,有能力的大家尽量支持Bitwarden官方:8bit Solutions LLC 公司 毕竟,开源项目要是脱离了商业支持,基本上活下去的都是奇迹。</p><p>bitwarden_rs 仅提供 API(服务器)端实现,用户仍依赖来自上游的客户端程序(移动应用程序、桌面应用程序和网页密码库),这些都是 8bit Solutions LLC 公司在上游完成的许多工作。</p><p>同时 bitwarden_rs 支持上游的某些付费功能并免费提供该功能。这就提出了一些有关<a href="https://github.com/dani-garcia/vaultwarden/issues/331">维持和支持上游发展</a>的问题。许多用户提出了这个问题,并咨询他们如何在使用 bitwarden_rs 的同时支持上游的发展。</p><p>您可以通过 <a href="https://www.paypal.me/bitwarden">PayPal</a> 直接捐赠给上游以支持他们的发展。</p><p><a href="https://github.com/dani-garcia/vaultwarden/wiki/Supporting-upstream">https://github.com/dani-garcia/vaultwarden/wiki/Supporting-upstream</a></p><p><a href="https://rs.bitwarden.in/other-information/supporting-upstream-development">https://rs.bitwarden.in/other-information/supporting-upstream-development</a></p><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p>构建容器镜像--中文文档: <a href="https://rs.bitwarden.in/deployment/building-your-own-docker-image">https://rs.bitwarden.in/deployment/building-your-own-docker-image</a></p><p>构建容器镜像--英文文档 <a href="https://github.com/dani-garcia/vaultwarden/wiki/Building-your-own-docker-image">https://github.com/dani-garcia/vaultwarden/wiki/Building-your-own-docker-image</a></p><p>启用https <a href="https://rs.bitwarden.in/deployment/https/enabling-https">https://rs.bitwarden.in/deployment/https/enabling-https</a></p><p><a href="https://github.com/dani-garcia/vaultwarden/wiki/Enabling-WebSocket-notifications">https://github.com/dani-garcia/vaultwarden/wiki/Enabling-WebSocket-notifications</a></p><p><a href="https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS">https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS</a></p><p>备份密码库 <a href="https://rs.bitwarden.in/other-information/backing-up-your-vault">https://rs.bitwarden.in/other-information/backing-up-your-vault</a></p><p>反向代理教程: <a href="https://rs.bitwarden.in/deployment/proxy-examples">https://rs.bitwarden.in/deployment/proxy-examples</a></p><p>禁用新用户注册 <a href="https://rs.bitwarden.in/configuration/disable-registration-of-new-users">https://rs.bitwarden.in/configuration/disable-registration-of-new-users</a></p><p>启用管理页面 <a href="https://rs.bitwarden.in/configuration/enabling-admin-page">https://rs.bitwarden.in/configuration/enabling-admin-page</a></p><p>Warning: Rocket&#x27;s built-in TLS is not considered ready for production use. It is intended for development use only.</p><p><a href="https://rocket.rs/v0.4/guide/configuration/#configuring-tls">https://rocket.rs/v0.4/guide/configuration/#configuring-tls</a></p><p><a href="https://github.com/dani-garcia/vaultwarden/wiki">https://github.com/dani-garcia/vaultwarden/wiki</a></p><p><a href="https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples">https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples</a></p><p><a href="https://bitwarden.com/help/article/import-from-firefox/">https://bitwarden.com/help/article/import-from-firefox/</a></p><p><a href="https://support.cloudflare.com/hc/en-us/articles/200170416-End-to-end-HTTPS-with-Cloudflare-Part-3-SSL-options#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef">https://support.cloudflare.com/hc/en-us/articles/200170416-End-to-end-HTTPS-with-Cloudflare-Part-3-SSL-options#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef</a></p><p><a href="https://www.techempower.com/benchmarks/#section=data-r20">https://www.techempower.com/benchmarks/#section=data-r20</a></p><p><a href="https://github.com/flosse/rust-web-framework-comparison#high-level-server-frameworks">https://github.com/flosse/rust-web-framework-comparison#high-level-server-frameworks</a></p><p>对比:<a href="https://www.iamzs.top/archives/comparison-among-three-password-managers.html">https://www.iamzs.top/archives/comparison-among-three-password-managers.html</a></p> Tue, 02 Mar 2021 14:58:32 GMT ttyS3 rustbitwardenpassword-managerdocker https://ttys3.dev/blog/setup-netlify-cms-for-hugo 为 Hugo 博客集成 Netlify CMS https://ttys3.dev/blog/setup-netlify-cms-for-hugo <h2 id="为什么需要-netlify-cms"><a href="#为什么需要-netlify-cms" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>为什么需要 Netlify CMS</h2><p>Netlify CMS 主要是解决了,随时随地打开浏览器写markdown博客的问题,同时它自动处理了图片上传等问题。</p><p>简单来说:</p><blockquote><p>Netlify CMS = web 版的 markdown 文件管理器 + 自动图片上传并插入markdown代码 + 在web浏览器写markdown并自动推送到git仓库构建 ....</p></blockquote><p>编辑器可以在富文本(所见即所得)和 Markdown 方式之间切换。 Markdown模式没有语法高亮显示,编辑起来略不方便。同时,切到 Markdown编辑模式后,编辑器的那些按钮都变灰不可用了。</p><p>Netlify CMS 只是附加功能,你完全可以在本地直接打开 NeoVim 或者 Emacs 写博客,然后用 Git push 发布文章。</p><p>代码编辑器可以自动折叠和伸展,支持选择语言,同时还支持选择是 <code>emacs</code> / <code>sublime</code> 还是 <code>vim</code> 编辑模式.</p><div><img alt="" src="https://ttys3.dev/static/assets/netlify-cms-code-block-editor-2021-03-02_21-18-TABEREDF.png" width="768" height="426"/></div><p>插入图片也非常方便,只是有一点,对于 Hugo <a href="https://gohugo.io/content-management/page-bundles/">Page Bundles</a> 是不支持的,因此图片只能是集中上传到一个目录下(也就是配置文件中指定的 <code>media_folder</code> 路径)。</p><div><img alt="" src="https://ttys3.dev/static/assets/netlify-cms-post-list-JRSCYTVM.jpg" width="1920" height="1048"/></div><div><img alt="" src="https://ttys3.dev/static/assets/netlify-cms-post-edit-4QN22BIE.jpg" width="1920" height="962"/></div><p>上传文件存相对目录 和 page bundle 支持,官方正式文档里并没有说明有这个功能。后来老灯发现这些新功能在beta版已经可用了 (beta 版的文档里有说明)。</p><p>beta 版的(最新版代码)可以去这里取: <a href="https://www.jsdelivr.com/package/npm/netlify-cms">https://www.jsdelivr.com/package/npm/netlify-cms</a></p><p>由于是开源的,因此也可以<a href="https://github.com/netlify/netlify-cms/blob/master/packages/netlify-cms/CHANGELOG.md">在这查看changelog</a></p><h2 id="部署方法"><a href="#部署方法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>部署方法</h2><p>需要创建一个<code>admin</code>目录,里面放一个<code>index.html</code> 文件作为后台管理的入口。 由于这个文件实际上也是要deploy到静态博客的,因此,我们要放在Hugo的 <code>static</code> 目录下。</p><p><code>static/admin/index.html</code> 内容如下:</p><div class="relative"><pre><code class="code-highlight language-html"><span class="code-line"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">doctype</span> <span class="token name">html</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>utf-8<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>viewport<span class="token punctuation">&quot;</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>width=device-width, initial-scale=1.0<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">&gt;</span></span>Blog Manager<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>https://identity.netlify.com/v1/netlify-identity-widget.js<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token comment">&lt;!-- Include the script that builds the page and powers Netlify CMS --&gt;</span> </span><span class="code-line"> <span class="token comment">&lt;!-- https://www.jsdelivr.com/package/npm/netlify-cms --&gt;</span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>https://cdn.jsdelivr.net/npm/[email protected]/dist/netlify-cms.min.js<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p><code>static/admin/config.yml</code> 内容如下:</p><div class="relative"><pre><code class="language-yaml code-highlight"><span class="code-line"><span class="token comment"># https://www.netlifycms.org/docs/add-to-your-site/</span> </span><span class="code-line"><span class="token atrule key">backend</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">name</span><span class="token punctuation">:</span> git<span class="token punctuation">-</span>gateway </span><span class="code-line"> <span class="token atrule key">branch</span><span class="token punctuation">:</span> main <span class="token comment"># Branch to update (optional; defaults to master)</span> </span><span class="code-line"> <span class="token atrule key">squash_merges</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token comment"># beta feature</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment"># when using the default proxy server port</span> </span><span class="code-line"> <span class="token comment"># Run npx netlify-cms-proxy-server from the root dir of the repo</span> </span><span class="code-line"><span class="token atrule key">local_backend</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 编辑工作流程</span> </span><span class="code-line"><span class="token atrule key">publish_mode</span><span class="token punctuation">:</span> editorial_workflow </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 全局静态文件上传目录</span> </span><span class="code-line"><span class="token atrule key">media_folder</span><span class="token punctuation">:</span> <span class="token string">&quot;static/img/uploads&quot;</span> <span class="token comment"># Media files will be stored in the repo under images/uploads</span> </span><span class="code-line"><span class="token atrule key">public_folder</span><span class="token punctuation">:</span> <span class="token string">&quot;/img/uploads&quot;</span> <span class="token comment"># The src attribute for uploaded media will begin with /images/uploads</span> </span><span class="code-line"> </span><span class="code-line"><span class="token atrule key">media_folder_relative</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token atrule key">collections</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;post&quot;</span> <span class="token comment"># Used in routes, e.g., /admin/collections/blog</span> </span><span class="code-line"> <span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Post&quot;</span> <span class="token comment"># Used in the UI</span> </span><span class="code-line"> <span class="token atrule key">folder</span><span class="token punctuation">:</span> <span class="token string">&quot;content/post&quot;</span> <span class="token comment"># The path to the folder where the documents are stored</span> </span><span class="code-line"> <span class="token atrule key">path</span><span class="token punctuation">:</span> <span class="token string">&#x27;{{slug}}/index&#x27;</span> <span class="token comment"># beta feature</span> </span><span class="code-line"> <span class="token atrule key">media_folder</span><span class="token punctuation">:</span> <span class="token string">&#x27;&#x27;</span> </span><span class="code-line"> <span class="token atrule key">public_folder</span><span class="token punctuation">:</span> <span class="token string">&#x27;&#x27;</span> </span><span class="code-line"> <span class="token comment"># adding a nested object will show the collection folder structure</span> </span><span class="code-line"> <span class="token atrule key">nested</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">depth</span><span class="token punctuation">:</span> <span class="token number">100</span> <span class="token comment"># max depth to show in the collection tree</span> </span><span class="code-line"> <span class="token atrule key">summary</span><span class="token punctuation">:</span> <span class="token string">&#x27;{{title}}&#x27;</span> <span class="token comment"># optional summary for a tree node, defaults to the inferred title field</span> </span><span class="code-line"> <span class="token comment"># adding a meta object with a path property allows editing the path of entries</span> </span><span class="code-line"> <span class="token comment"># moving an existing entry will move the entire sub tree of the entry to the new location</span> </span><span class="code-line"> <span class="token atrule key">meta</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token atrule key">path</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> string<span class="token punctuation">,</span> <span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&#x27;Path&#x27;</span><span class="token punctuation">,</span> <span class="token atrule key">index_file</span><span class="token punctuation">:</span> <span class="token string">&#x27;index&#x27;</span><span class="token punctuation">,</span> <span class="token atrule key">hint</span><span class="token punctuation">:</span> &#x27;markdown文件路径<span class="token punctuation">,</span> 对于page bundle<span class="token punctuation">,</span> 如 &quot;一级目录/二级目录/page<span class="token punctuation">-</span>bundle目录/index.md&quot;<span class="token punctuation">,</span> 只需要填写 &quot;一级目录/二级目录/page<span class="token punctuation">-</span>bundle目录&quot;<span class="token punctuation">,</span>不 </span><span class="code-line">要忘记填写page<span class="token punctuation">-</span>bundle目录&#x27; <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">create</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token comment"># Allow users to create new documents in this collection</span> </span><span class="code-line"> <span class="token atrule key">slug</span><span class="token punctuation">:</span> <span class="token string">&quot;{{year}}-{{month}}-{{day}}-{{slug}}&quot;</span> <span class="token comment"># Filename template, e.g., YYYY-MM-DD-title.md</span> </span><span class="code-line"> <span class="token atrule key">fields</span><span class="token punctuation">:</span> <span class="token comment"># The fields for each document, usually in front matter</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Title&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;title&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">hint</span><span class="token punctuation">:</span> <span class="token string">&quot;文章标题&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Slug&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;slug&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">required</span><span class="token punctuation">:</span> <span class="token boolean important">false</span><span class="token punctuation">,</span> <span class="token atrule key">hint</span><span class="token punctuation">:</span> <span class="token string">&quot;Slug可以是目录,如 linux/archlinux, 此项会作为路径的功能可能会被 path meta 覆盖&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Comments&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;comments&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> <span class="token string">&quot;boolean&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">default</span><span class="token punctuation">:</span> <span class="token boolean important">true</span><span class="token punctuation">,</span> <span class="token atrule key">hint</span><span class="token punctuation">:</span> <span class="token string">&quot;true 允许评论, false 禁止评论&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Draft&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;draft&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> <span class="token string">&quot;boolean&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">default</span><span class="token punctuation">:</span> <span class="token boolean important">true</span><span class="token punctuation">,</span> <span class="token atrule key">hint</span><span class="token punctuation">:</span> <span class="token string">&quot;草稿不会 build&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Publish Date&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;date&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> <span class="token string">&quot;datetime&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Featured Image&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;cover&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> <span class="token string">&quot;image&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">required</span><span class="token punctuation">:</span> <span class="token boolean important">false</span><span class="token punctuation">,</span> <span class="token atrule key">hint</span><span class="token punctuation">:</span> <span class="token string">&quot;封面图片&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Tags&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;tags&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> <span class="token string">&quot;list&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">required</span><span class="token punctuation">:</span> <span class="token boolean important">false</span><span class="token punctuation">,</span> <span class="token string">&quot;文章标签,用半角逗号分隔&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">label</span><span class="token punctuation">:</span> <span class="token string">&quot;Body&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;body&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">widget</span><span class="token punctuation">:</span> <span class="token string">&quot;markdown&quot;</span><span class="token punctuation">,</span> <span class="token atrule key">hint</span><span class="token punctuation">:</span> <span class="token string">&quot;博客正文&quot;</span><span class="token punctuation">}</span> </span></code></pre></div><blockquote><p>注意,以上配置用于 Page bundle 模式写博客。如果设置了 <code>slug , 则</code>slug<code>一定要与</code>path` 的最后一部分(&quot;一级目录/二级目录/page-bundle目录&quot; 中的 &quot;page-bundle目录&quot;)相同,不然引入的图片路径就会不对。</p></blockquote><p>这里的 <code>comments</code> 是老灯主题的自定义字段,表示文章是否允许评论。<code>cover</code> 字段也是主题里定义的,表示文章封面图。如果拿过去用,注意稍修改一下适配你自己的主题。</p><p>当前这个配置支持:</p><ol><li>全局静态文件上传到 <code>static/img/uploads</code></li><li>仅支持 page bundle 模式写文章(这也是老灯认为唯一适合的文件组织方式)</li><li>由于支持 page bundle,因此,文章图片上传也是上传到 page bundle 的目录。</li><li>支持 Netlify CMS 本地仓库模式</li></ol><h2 id="本地git仓库模式"><a href="#本地git仓库模式" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>本地Git仓库模式</h2><p>Working with a Local Git Repository <a href="https://www.netlifycms.org/docs/beta-features/#working-with-a-local-git-repository">https://www.netlifycms.org/docs/beta-features/#working-with-a-local-git-repository</a></p><p>简单启用,只需要在 <code>config.yml</code> 中添加 <code>local_backend: true</code> 即可。 然后 <code>npx netlify-cms-proxy-server</code> 启动 proxy 即可,它默认监听 <code>8081</code> 端口。 然后通过 <code>hugo serve</code> 启动,然后访问 <a href="http://localhost:1313/admin/">http://localhost:1313/admin/</a> 即可。</p><p>如果要自定义端口,你需要在 Hugo 项目的根目录下新建一 <code>.env</code> 文件,内容如下:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token assign-left variable">PORT</span><span class="token operator">=</span><span class="token number">8082</span> </span></code></pre></div><p>然后更新 <code>config.yml</code> 中的 <code>local_backend</code> 对象配置:</p><div class="relative"><pre><code class="language-yaml code-highlight"><span class="code-line"><span class="token atrule key">backend</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">name</span><span class="token punctuation">:</span> git<span class="token punctuation">-</span>gateway </span><span class="code-line"> </span><span class="code-line"><span class="token atrule key">local_backend</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token comment"># when using a custom proxy server port</span> </span><span class="code-line"> <span class="token atrule key">url</span><span class="token punctuation">:</span> http<span class="token punctuation">:</span>//localhost<span class="token punctuation">:</span>8082/api/v1 </span><span class="code-line"> <span class="token comment"># when accessing the local site from a host other than &#x27;localhost&#x27; or &#x27;127.0.0.1&#x27;</span> </span><span class="code-line"> <span class="token comment"># allowed_hosts: [&#x27;192.168.0.1&#x27;]</span> </span></code></pre></div><p>如果需要允许局域网其它电脑访问,可以添加 <code>allowed_hosts</code> 配置。</p><h2 id="toubleshoot"><a href="#toubleshoot" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>toubleshoot</h2><p>关于配置</p><p>Bool类型的一定要写<code>true</code> 和 <code>false</code>, 不要写成了字符串。不然后台会报错:</p><blockquote><p>Error loading the CMS configuration Config Errors: &#x27;collections[0].fields[4].required&#x27; should be boolean Check your config.yml file.</p></blockquote><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://zhuanlan.zhihu.com/p/56319868">https://zhuanlan.zhihu.com/p/56319868</a></p><p><a href="https://www.netlifycms.org/docs/add-to-your-site/">https://www.netlifycms.org/docs/add-to-your-site/</a></p><p><a href="https://www.netlifycms.org/docs/widgets/">https://www.netlifycms.org/docs/widgets/</a></p><p><a href="https://www.netlifycms.org/docs/beta-features/#folder-collections-media-and-public-folder">https://www.netlifycms.org/docs/beta-features/#folder-collections-media-and-public-folder</a></p><p><a href="https://www.netlifycms.org/docs/configuration-options/">https://www.netlifycms.org/docs/configuration-options/</a></p><h2 id="其它"><a href="#其它" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它</h2><p>关于 <strong>Page Bundles</strong> 的支持问题,已经有人提issue了,见:</p><p><a href="https://github.com/netlify/netlify-cms/issues/1697">https://github.com/netlify/netlify-cms/issues/1697</a></p><p><a href="https://github.com/netlify/netlify-cms/issues/513">https://github.com/netlify/netlify-cms/issues/513</a></p><p><a href="https://github.com/netlify/netlify-cms/issues/1472">Store Assets Relative to Content (Bundles) #1472</a></p><p><a href="https://github.com/netlify/netlify-cms/issues/1472#issuecomment-557927885">https://github.com/netlify/netlify-cms/issues/1472#issuecomment-557927885</a></p><blockquote><p>Hi everyone ! Does anyone know if this feature is implemented? This is the only thing preventing us from using Netlify CMS in our project... and the documentation is not clear on what the option <code>media_folder_relative: true</code> allows to do. Thanks for the help :)</p></blockquote><p><a href="https://github.com/netlify/netlify-cms/issues/2696#issuecomment-614544868">https://github.com/netlify/netlify-cms/issues/2696#issuecomment-614544868</a></p><p>Closing as <code>media_folder_relative</code> was removed in favour of <a href="https://www.netlifycms.org/docs/beta-features/#folder-collections-media-and-public-folder">https://www.netlifycms.org/docs/beta-features/#folder-collections-media-and-public-folder</a></p><p><a href="https://github.com/netlify/netlify-cms/issues/3227">https://github.com/netlify/netlify-cms/issues/3227</a></p><p><a href="https://github.com/netlify/netlify-cms/issues/1472#issuecomment-559376878">https://github.com/netlify/netlify-cms/issues/1472#issuecomment-559376878</a></p><blockquote><p>Latest code on master branch (not published yet to beta) lets you do:</p></blockquote><div class="relative"><pre><code class="language-yaml code-highlight"><span class="code-line"><span class="token atrule key">slug</span><span class="token punctuation">:</span> <span class="token string">&#x27;index&#x27;</span> </span><span class="code-line"><span class="token atrule key">path</span><span class="token punctuation">:</span> <span class="token string">&#x27;{{title}}/{{slug}}&#x27;</span> </span></code></pre></div><p>to save a file under <code>title/index.md</code> for example.</p><p>Next step will be to store images with the content.</p><p>相关已经合并 PR: <a href="https://github.com/netlify/netlify-cms/pull/2958">https://github.com/netlify/netlify-cms/pull/2958</a></p> Tue, 02 Mar 2021 12:43:28 GMT ttyS3 testnetlifyhugo https://ttys3.dev/blog/portainer-ce-2.1.1-init-support-podman Portainer CE 2.1.1 Initial Support Podman https://ttys3.dev/blog/portainer-ce-2.1.1-init-support-podman <p><strong>Portainer</strong> 是一个比较流行的Docker web ui, Docker 官方只针对Windows/Mac 有GUI支持,对于Linux则靠民间的UI了。</p><p>事实上,<strong>Portainer</strong> 应该是仅存的少数 功能较完善且开发活跃的第三方 Docker UI之一.</p><p>另一个WEB UI 是RedHat 家的 cockpit (准确来说,应该叫Redhat赞助的, 不过老灯感觉区别不大), 除了管理docker容器,cockpit还支持 podman和虚拟机管理,磁盘管理等其它功能,因此它是一个dashboard, 而不是单纯的容器管理UI.</p><p>关于对podman的支持,Github早有讨论, 见 <a href="https://github.com/portainer/portainer/issues/2991">https://github.com/portainer/portainer/issues/2991</a></p><p>一开始, Podman 用了一个偏门的叫varlink的协议,后面还是考虑了民间的需求,推出了<a href="https://podman.io/blogs/2020/01/17/podman-new-api.html">Docker compatible API for Podman</a></p><p><a href="https://podman.io/blogs/2020/06/29/podman-v2-announce.html">https://podman.io/blogs/2020/06/29/podman-v2-announce.html</a></p><blockquote><p>In keeping with Podman’s history the restful API will work in both rootless and rootfull mode. If you run in rootfull mode, the podman service will listen on /run/podman/podman.sock and rootless is $XDG_RUNTIME_DIR/podman/podman.sock (for example: /run/user/1000/podman/podman.sock). If you install the podman-docker package, the package will set up a link between <code>/run/docker/docker.sock</code> and <code>/run/podman/podman.sock</code>.</p></blockquote><p>根据<a href="https://github.com/portainer/portainer/issues/2991#issuecomment-742225288">Portainer作者的回答</a>:</p><blockquote><p>As Podman is Docker API 1.40 compliant, when we release Portainer CE 2.1, which will itself support the latest Docker API (currently we only support an older API ver), we are hopeful this will work.</p></blockquote><p>作者的意思: 当前 2.0 版本的Portainer 只支持比较老的Docker Restful API, 要 2.1 才会支持 Docker API 1.40</p><p>Portainer 不会支持 Podman, 只会支持兼容Docker API 的东西。</p><p>也就是说, Podman 的API 如果和 Docker 的不兼容,Portainer 就可能不能正常工作.</p><p>如今 2.1.1 版本的 Portainer 已经发布了,于是老灯尝试了一下Portainer 对于 Podman 的支持.</p><p>以下仅讨论Root模式,Rootless模式由于坑太多,不太建议尝试。</p><p>首先,启用Podman restful API daemon:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> systemctl <span class="token class-name builtin">enable</span> <span class="token parameter variable">--now</span> podman.socket </span></code></pre></div><p>测试一下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">$ <span class="token function">sudo</span> <span class="token function">curl</span> <span class="token parameter variable">-H</span> <span class="token string">&quot;Content-Type: application/json&quot;</span> --unix-socket /var/run/docker.sock http://localhost/_ping </span><span class="code-line">OK </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">sudo</span> <span class="token function">curl</span> <span class="token parameter variable">-H</span> <span class="token string">&quot;Content-Type: application/json&quot;</span> --unix-socket /var/run/podman/podman.sock http://localhost/_ping </span><span class="code-line">OK </span></code></pre></div><p>部署Portainer</p><p>根据官方文档 <a href="https://documentation.portainer.io/v2.0/deploy/ceinstalldocker/">https://documentation.portainer.io/v2.0/deploy/ceinstalldocker/</a> :</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">podman</span> volume create portainer_data </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 注意,这里我映射到了9001端口,因为9000已经给Docker的Portainer使用了.</span> </span><span class="code-line"><span class="token comment"># 8000也是常用端口,不应该给Portainer占用了,因此这里我用的8041</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">podman</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">-p</span> <span class="token number">8041</span>:8000 <span class="token parameter variable">-p</span> <span class="token number">9001</span>:9000 <span class="token parameter variable">--name</span><span class="token operator">=</span>portainer <span class="token punctuation">\</span> </span><span class="code-line"><span class="token parameter variable">-v</span> /var/run/podman/podman.sock:/var/run/docker.sock <span class="token punctuation">\</span> </span><span class="code-line"><span class="token parameter variable">-v</span> portainer_data:/data portainer/portainer-ce </span></code></pre></div><p>注意这里的sock路径我特意用的<code>/var/run/podman/podman.sock</code>.</p><p>执行成功后,打开 <code>http://localhost:9001/</code>, 然后发现有个错误: Failure: Unable to proxy the request via the Docker socket</p><p>打开浏览器控制台查看了下,以下为错误原因:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">GET</span> <span class="token operator">/</span>api<span class="token operator">/</span>endpoints<span class="token operator">/</span><span class="token number">2</span><span class="token operator">/</span>docker<span class="token operator">/</span>networks </span><span class="code-line"> </span><span class="code-line"><span class="token number">500</span> <span class="token maybe-class-name">Internal</span> <span class="token maybe-class-name">Server</span> <span class="token class-name known-class-name">Error</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"><span class="token property string-property">&quot;message&quot;</span><span class="token operator">:</span><span class="token string">&quot;Unable to proxy the request via the Docker socket&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token property string-property">&quot;details&quot;</span><span class="token operator">:</span><span class="token string">&quot;unable to find bridge plugin&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>还有一个404错误:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">GET</span> <span class="token operator">/</span>api<span class="token operator">/</span>endpoints<span class="token operator">/</span><span class="token number">2</span><span class="token operator">/</span>docker<span class="token operator">/</span>plugins </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">{</span><span class="token property string-property">&quot;cause&quot;</span><span class="token operator">:</span><span class="token string">&quot;&quot;</span><span class="token punctuation">,</span><span class="token property string-property">&quot;message&quot;</span><span class="token operator">:</span><span class="token string">&quot;Path /plugins is not supported&quot;</span><span class="token punctuation">,</span><span class="token property string-property">&quot;response&quot;</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span> </span><span class="code-line"> </span></code></pre></div><p>大概体验了一下,网络管理不可用,image, container 和 volume 列表显示OK. 删除功能OK.</p><p>无法查看container log, 无法进入console. 因此,目前来说,这个还达不到基本的可用标准。</p><p>很多基本功能不工作。</p><div><img alt="portainer-podman-host-overview.png" src="https://ttys3.dev/static/assets/portainer-podman-host-overview-MGL75P2F.png" width="1367" height="1144"/></div><p>Podman 版本信息:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">Version: <span class="token number">2.2</span>.1 </span><span class="code-line">API Version: <span class="token number">2.1</span>.0 </span><span class="code-line">Go Version: go1.15.5 </span><span class="code-line">Git Commit: a0d478edea7f775b7ce32f8eb1a01e75374486cb </span><span class="code-line">Built: Thu Dec <span class="token number">10</span> 03:08:37 <span class="token number">2020</span> </span><span class="code-line">OS/Arch: linux/amd64 </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://documentation.portainer.io/v2.0/deploy/ceinstalldocker/">https://documentation.portainer.io/v2.0/deploy/ceinstalldocker/</a></p> Tue, 16 Feb 2021 12:31:36 GMT ttyS3 portainerpodman https://ttys3.dev/blog/podman-now-support-firewalld-rules-reload Podman Now Support Firewalld Rules Reload https://ttys3.dev/blog/podman-now-support-firewalld-rules-reload <p>这个问题其实 docker 和 podman 都存在。</p><p>当前版本的 docker 采用 iptables 动态创建和销毁规则, 而 podman 则通过<a href="https://github.com/containernetworking/cni">CNI</a> 插件配置, 可以使用 firewalld 作为backend.</p><p>由于容器的特性-- 随时创建,随时销毁。 这二者添加的 iptables 规则自然也都是动态的。这里有个问题是,如果一些其它服务执行了 flush 操作把iptables 规则清空了,则bridge网络的容器端口转发就会失效, 因为我们通过 <code>-p</code> 来映射端口,实际上是在 iptables 的 nat 表里创建了转发规则。</p><p>podman Github 有一个相关issue <a href="https://github.com/containers/podman/issues/5431">https://github.com/containers/podman/issues/5431</a> 已经半年多了,不过最近一看,发现问题以另外一种方式解决了。</p><p>比如有人提到问题产生的场景:</p><blockquote><p>Regarding the reload thing, on Fedora, NetworkManager has this postinstall line: <code>test -f /usr/bin/firewall-cmd &amp;&amp; firewall-cmd --reload --quiet || :</code> Meaning when you upgrade the package, you lose rules created by podman.</p></blockquote><p>解决方案就是给<code>network</code>命令新增加了一个<code>reload</code> 的子命令, 即 <code>podman network reload</code>.</p><p>这个命令的作用是,当你发现iptables 规则被flush掉后(对于Fedora是nft 规则), 可以用这个命令来修复缺失的规则. 而以前的做法是,只能销毁容器并重建, 有了这个reload命令,确实方便了许多。</p><blockquote><p>Yes it was <a href="https://github.com/containers/podman/pull/8571">#8571</a>. We now have the podman network reload command to recreate the iptables rules. This does not make the rules permanent but if they are deleted after a firewall reload you can run this command with the --all option to recreate the rules without having to restart containers.</p></blockquote><p>PR 是在 Dec 8, 2020 merge的, 这个merge被包含在当前最新的 <a href="https://github.com/containers/podman/releases/tag/v3.0.0">3.0.0版</a> 中.</p><blockquote><p>A new command, podman network reload, has been added. This command will re-configure the network of all running containers, and can be used to recreate firewall rules lost when the system firewall was reloaded (e.g. via firewall-cmd --reload).</p></blockquote><p>命令用法:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token function">podman</span> network reload <span class="token punctuation">[</span>CONTAINER<span class="token punctuation">..</span>.<span class="token punctuation">]</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 针对所有容器用-a参数</span> </span><span class="code-line"><span class="token function">podman</span> network reload <span class="token parameter variable">-a</span> </span></code></pre></div><h2 id="关于podman-cni-firewall-插件-配置"><a href="#关于podman-cni-firewall-插件-配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>关于podman cni firewall 插件 配置</h2><p>cni 默认有一些内置插件,放在单独的仓库 <a href="https://github.com/containernetworking/plugins">https://github.com/containernetworking/plugins</a> , 这里我们用到的 <a href="https://www.cni.dev/plugins/meta/firewall/">firewall</a> 插件就是其中之一。</p><p>编辑 <code>/etc/cni/net.d/87-podman-bridge.conflist</code> 修改<code>firewall</code>类型的<code>backend</code> 为 <code>firewalld</code> 即可启用firewalld作为防火墙规则后端:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;firewall&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;backend&quot;</span><span class="token operator">:</span> <span class="token string">&quot;firewalld&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span></code></pre></div><p>取值来自 <a href="https://github.com/containernetworking/plugins/blob/fa48f7515b50272b7106702a662fadbf2ead3d18/plugins/meta/firewall/firewall.go#L33">plugins/meta/firewall/firewall.go</a></p><div class="relative"><pre><code class="code-highlight language-go"><span class="code-line"><span class="token comment">// FirewallNetConf represents the firewall configuration.</span> </span><span class="code-line"><span class="token keyword">type</span> FirewallNetConf <span class="token keyword">struct</span> <span class="token punctuation">{</span> </span><span class="code-line"> types<span class="token punctuation">.</span>NetConf </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// Backend is the firewall type to add rules to. Allowed values are</span> </span><span class="code-line"> <span class="token comment">// &#x27;iptables&#x27; and &#x27;firewalld&#x27;.</span> </span><span class="code-line"> Backend <span class="token builtin">string</span> <span class="token string">`json:&quot;backend&quot;`</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// ...</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>其实不配置也OK, <a href="https://github.com/containernetworking/plugins/blob/fa48f7515b50272b7106702a662fadbf2ead3d18/plugins/meta/firewall/firewall.go#L96">默认逻辑</a>是:</p><blockquote><p>Default to firewalld if it&#x27;s running, Otherwise iptables</p></blockquote><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://github.com/containernetworking/cni">https://github.com/containernetworking/cni</a></p><p><a href="https://github.com/containernetworking/plugins">https://github.com/containernetworking/plugins</a></p><p><a href="https://www.cni.dev/plugins/meta/firewall/">https://www.cni.dev/plugins/meta/firewall/</a></p> Tue, 16 Feb 2021 10:24:18 GMT ttyS3 podmanfirewalld https://ttys3.dev/blog/rust-cross-compile-for-windows-target-under-linux Rust Cross Compile for Windows target under Linux https://ttys3.dev/blog/rust-cross-compile-for-windows-target-under-linux <h2 id="environment"><a href="#environment" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Environment</h2><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">OS</span><span class="token operator">:</span> <span class="token maybe-class-name">Fedora</span> <span class="token number">33</span> <span class="token punctuation">(</span><span class="token maybe-class-name">Workstation</span> <span class="token maybe-class-name">Edition</span><span class="token punctuation">)</span> x86_64 </span><span class="code-line"><span class="token constant">CPU</span><span class="token operator">:</span> <span class="token function"><span class="token maybe-class-name">Intel</span></span><span class="token punctuation">(</span><span class="token constant">R</span><span class="token punctuation">)</span> <span class="token function"><span class="token maybe-class-name">Core</span></span><span class="token punctuation">(</span><span class="token constant">TM</span><span class="token punctuation">)</span> i7<span class="token operator">-</span>8700K <span class="token constant">CPU</span> @ <span class="token number">3</span><span class="token punctuation">.</span>70GHz x86_64 </span><span class="code-line"><span class="token literal-property property">rustc</span><span class="token operator">:</span> <span class="token number">1.49</span><span class="token number">.0</span> <span class="token punctuation">(</span>e1884a8e3 <span class="token number">2020</span><span class="token operator">-</span><span class="token number">12</span><span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token literal-property property">cargo</span><span class="token operator">:</span> <span class="token number">1.49</span><span class="token number">.0</span> <span class="token punctuation">(</span>d00d64df9 <span class="token number">2020</span><span class="token operator">-</span><span class="token number">12</span><span class="token operator">-</span><span class="token number">05</span><span class="token punctuation">)</span> </span></code></pre></div><h2 id="requirements"><a href="#requirements" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Requirements</h2><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># Install build dependencies</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> mingw64-gcc </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> mingw64-winpthreads-static </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Add Windows Rust target</span> </span><span class="code-line">rustup target <span class="token function">add</span> x86_64-pc-windows-gnu </span><span class="code-line">rustup toolchain <span class="token function">install</span> stable-x86_64-pc-windows-gnu </span></code></pre></div><h2 id="building"><a href="#building" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Building</h2><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">cargo</span> new hello </span><span class="code-line"><span class="token builtin class-name">cd</span> hello </span><span class="code-line"><span class="token function">cargo</span> build <span class="token variable parameter">--target</span> x86_64-pc-windows-gnu </span></code></pre></div><p>交叉编译默认的hello world, 需要链接 <code>libpthread.a</code>, 如果上面我们没有安装 <code>mingw64-winpthreads-static</code> 包,则会在链接时产生一个错误:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">cargo</span> build <span class="token variable parameter">--target</span> x86_64-pc-windows-gnu </span><span class="code-line"> Compiling hello v0.1.0 <span class="token punctuation">(</span>/tmp/hello/hello<span class="token punctuation">)</span> </span><span class="code-line">error: linking with <span class="token variable"><span class="token variable">`</span>x86_64-w64-mingw32-gcc<span class="token variable">`</span></span> failed: <span class="token builtin class-name">exit</span> code: <span class="token number">1</span> </span><span class="code-line"><span class="token punctuation">..</span>. </span><span class="code-line"> <span class="token operator">=</span> note: /usr/lib/gcc/x86_64-w64-mingw32/10.2.1/<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/x86_64-w64-mingw32/bin/ld: cannot <span class="token function">find</span> <span class="token variable parameter">-l:libpthread.a</span> </span><span class="code-line"> collect2: error: ld returned <span class="token number">1</span> <span class="token builtin class-name">exit</span> status </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">error: aborting due to previous error </span><span class="code-line"> </span><span class="code-line">error: could not compile <span class="token variable"><span class="token variable">`</span>hello<span class="token variable">`</span></span> </span><span class="code-line"> </span><span class="code-line">To learn more, run the <span class="token builtin class-name">command</span> again with --verbose. </span></code></pre></div><p>遇到这种问题解决一般也比较简单,以mingw64为关键字搜索,安装对应的静态库就好了,</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> dnf search mingw64 <span class="token operator">|</span> rg pthread </span><span class="code-line">Last metadata expiration check: <span class="token number">0</span>:57:48 ago on Mon <span class="token number">25</span> Jan <span class="token number">2021</span> 01:43:34 AM CST. </span><span class="code-line">mingw64-winpthreads.noarch <span class="token builtin class-name">:</span> MinGW pthread library <span class="token keyword">for</span> the win64 target </span><span class="code-line">mingw64-winpthreads-static.noarch <span class="token builtin class-name">:</span> Static version of the MinGW Windows pthreads library </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">sudo</span> dnf <span class="token function">install</span> mingw64-winpthreads-static </span></code></pre></div><h2 id="misc"><a href="#misc" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Misc</h2><h3 id="gnu-vs-msvc"><a href="#gnu-vs-msvc" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>gnu vs msvc</h3><p>Difference between the gnu and msvc toolchains?</p><blockquote><p>The GNU toolchain uses the MinGW build tools (mostly the linker) and produces binaries that use the GNU ABI. The MSVC toolchain uses the Visual Studio build tools and produces binaries that use the Microsoft ABI, making them more compatible with most other Windows binaries/libraries.</p></blockquote><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://www.reddit.com/r/rust/comments/a63dlt/difference_between_the_gnu_and_msvc_toolchains/">https://www.reddit.com/r/rust/comments/a63dlt/difference_between_the_gnu_and_msvc_toolchains/</a></p><p><a href="https://rust-lang.github.io/rustup/installation/windows.html">https://rust-lang.github.io/rustup/installation/windows.html</a></p> Sun, 24 Jan 2021 16:53:36 GMT ttyS3 rustwindowscompilemingw64cross-compilelinux https://ttys3.dev/blog/rust-cross-compile-mac-osx-target-under-linux Rust Cross Compile OSX target under Linux https://ttys3.dev/blog/rust-cross-compile-mac-osx-target-under-linux <blockquote><p>this article first post on 2021-01-25 updated on 2023-08-28</p></blockquote><p>起因主要是想给我fork自convco的<a href="https://github.com/ttys3/git-cz">git-cz</a> 项目 release 那里增加一个Mac二进制文件方便使用Mac的人下载。</p><p>这是一个方便使用约定式提交记录的git工具.</p><div><img alt="git-cz-screen-record.gif " src="https://ttys3.dev/static/assets/git-cz-screen-record-EQIM3QTY.gif" width="906" height="553"/></div><h2 id="environment"><a href="#environment" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Environment</h2><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token constant">OS</span><span class="token operator">:</span> <span class="token maybe-class-name">Fedora</span> <span class="token number">38</span> <span class="token punctuation">(</span><span class="token maybe-class-name">Workstation</span> <span class="token maybe-class-name">Edition</span><span class="token punctuation">)</span> x86_64 </span><span class="code-line"><span class="token constant">CPU</span><span class="token operator">:</span> <span class="token function"><span class="token maybe-class-name">Intel</span></span><span class="token punctuation">(</span><span class="token constant">R</span><span class="token punctuation">)</span> <span class="token function"><span class="token maybe-class-name">Core</span></span><span class="token punctuation">(</span><span class="token constant">TM</span><span class="token punctuation">)</span> i7<span class="token operator">-</span>8700K <span class="token constant">CPU</span> @ <span class="token number">3</span><span class="token punctuation">.</span>70GHz x86_64 </span><span class="code-line">rustc <span class="token number">1.72</span><span class="token number">.0</span> <span class="token punctuation">(</span>5680fa18f <span class="token number">2023</span><span class="token operator">-</span><span class="token number">08</span><span class="token operator">-</span><span class="token number">23</span><span class="token punctuation">)</span> </span><span class="code-line">cargo <span class="token number">1.72</span><span class="token number">.0</span> <span class="token punctuation">(</span>103a7ff2e <span class="token number">2023</span><span class="token operator">-</span><span class="token number">08</span><span class="token operator">-</span><span class="token number">15</span><span class="token punctuation">)</span> </span></code></pre></div><h2 id="requirements"><a href="#requirements" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Requirements</h2><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># Install build dependencies</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># CentOS Stream / Fedora 38</span> </span><span class="code-line">dnf group <span class="token function">install</span> <span class="token string">&quot;Development Tools&quot;</span> </span><span class="code-line"> </span><span class="code-line">dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> <span class="token punctuation">\</span> </span><span class="code-line"> clang-devel clang <span class="token punctuation">\</span> </span><span class="code-line"> gcc <span class="token punctuation">\</span> </span><span class="code-line"> gcc-c++ <span class="token punctuation">\</span> </span><span class="code-line"> zlib-devel <span class="token punctuation">\</span> </span><span class="code-line"> libmpc-devel <span class="token punctuation">\</span> </span><span class="code-line"> mpfr-devel <span class="token punctuation">\</span> </span><span class="code-line"> gmp-devel </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Ubuntu 23.04</span> </span><span class="code-line"><span class="token function">apt</span> <span class="token function">install</span> <span class="token punctuation">\</span> </span><span class="code-line"> clang <span class="token punctuation">\</span> </span><span class="code-line"> gcc <span class="token punctuation">\</span> </span><span class="code-line"> g++ <span class="token punctuation">\</span> </span><span class="code-line"> zlib1g-dev <span class="token punctuation">\</span> </span><span class="code-line"> libmpc-dev <span class="token punctuation">\</span> </span><span class="code-line"> libmpfr-dev <span class="token punctuation">\</span> </span><span class="code-line"> libgmp-dev </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Add macOS Rust target</span> </span><span class="code-line">rustup target <span class="token function">add</span> x86_64-apple-darwin </span></code></pre></div><h2 id="building-osxcross-toolchain"><a href="#building-osxcross-toolchain" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Building OSXCross Toolchain</h2><p>OSXCross 是什么? 是一个快速让你在Linux上安装Mac交叉编译toolchain的工具。</p><p>很多复杂或麻烦的事情都被它处理好了。</p><p>它甚至还带了一个包管理器:</p><blockquote><p>OSXCross comes with a minimalistic MacPorts Packet Manager. See <a href="https://github.com/tpoechtrager/osxcross/blob/master/README.MACPORTS.md">README.MACPORTS</a> for more.</p></blockquote><p>安装步骤:</p><h3 id="1-准备-sdk"><a href="#1-准备-sdk" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. 准备 SDK</h3><p>这步骤主要参考: <a href="https://github.com/tpoechtrager/osxcross#packaging-the-sdk">https://github.com/tpoechtrager/osxcross#packaging-the-sdk</a></p><p>-- Xcode up to 15 Beta 6 is known to work. -- Use Firefox if you have problems signing in.</p><p>osxcross now support the latest Xcode 15 Beta 6, that&#x27;s good.</p><p>构建这个toolchain需要苹果的SDK, 这个需要从Xcode提取。 去 <a href="https://developer.apple.com/download/all/">https://developer.apple.com/download/all/</a> 下载最新版的Xcode (需要Apple ID登录), beta版的不需要从app store下载,下载回来是一个<code>xip</code>后缀的文件.</p><p>我这里下载当前最新的最低可以支持到较旧版本的 macOS 12 的 Xcode 版本 <code>Xcode_14.2.xip</code></p><p>according to <a href="https://xcodereleases.com/?scope=release">https://xcodereleases.com/?scope=release</a></p><p>the latest Xcode we can use to support macOS 12 is: Xcode 14.2</p><table><thead><tr><th>Version</th><th>Released</th><th>Requires</th><th>SDKs</th></tr></thead><tbody><tr><td>Xcode 15.0 Beta 7</td><td>22 Aug 2023</td><td>macOS 13.4+</td><td>macOS 14.0 (23A5326c)</td></tr><tr><td>Xcode 14.3</td><td>30 Mar 2023</td><td>macOS 13.0+</td><td>macOS 13.3 (22E245)</td></tr><tr><td>Xcode 14.2</td><td>13 Dec 2022</td><td>macOS 12.5+</td><td>macOS 13.1 (22C55)</td></tr><tr><td>Xcode 13.2.1</td><td>17 Dec 2021</td><td>macOS 11.3+</td><td>macOS 12.1 (21C46)</td></tr></tbody></table><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">https://download.developer.apple.com/Developer_Tools/Xcode_14.2/Xcode_14.2.xip </span></code></pre></div><p>ps: 老灯还发现了一个下载 xcode 的好地方: <a href="https://xcodereleases.com/">https://xcodereleases.com/</a></p><p>Packing the SDK on Linux - Method 1 (Xcode &gt; 8.0):</p><p>确保已经安装了打包SDK过程中需要的clang, make, libssl-devel, lzma-devel and libxml2-devel</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"> </span><span class="code-line"><span class="token comment"># 如果之前有下载过, 记得删除 rm -rf osxcross , 不然连接的旧的库可能会导致 pbzx 等无法执行</span> </span><span class="code-line"><span class="token function">git</span> clone https://github.com/tpoechtrager/osxcross </span><span class="code-line"><span class="token class-name builtin">cd</span> osxcross </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># ubuntu lzma.h: sudo apt install -y liblzma-dev</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># /home/ttys3/Downloads/Compressed/Xcode_14.2.xip 是下载好的 `Xcode_14.2.xip` 路径</span> </span><span class="code-line"><span class="token comment"># size almost 7.1 GB</span> </span><span class="code-line">./tools/gen_sdk_package_pbzx.sh /home/ttys3/Downloads/Compressed/Xcode_14.2.xip </span></code></pre></div><p>这里需要解包 xip 文档,再用xz 打包, 要一小会。</p><blockquote><p>took 9m25s max disk usage: 29 GB</p></blockquote><p>打包成功会在 OSXCross 根目录下生成 <code>MacOSX13.1.sdk.tar.xz</code> and <code>MacOSX13.sdk.tar.xz</code></p><p>将 <code>MacOSX13.1.sdk.tar.xz</code> 移动到<code>tarballs</code> 目录下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">mv</span> MacOSX13.1.sdk.tar.xz ./tarballs </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># we do not need MacOSX13.sdk.tar.xz</span> </span><span class="code-line"><span class="token function">rm</span> MacOSX13.sdk.tar.xz </span></code></pre></div><h3 id="2-构建toolchain"><a href="#2-构建toolchain" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. 构建toolchain</h3><p>确保你的系统已经安装了必要的组件,如 Clang 3.9+, cmake, git, patch, Python, libssl-devel (openssl) lzma-devel, libxml2-devel and the bash shell</p><p>可选: Optional:</p><p>llvm-devel: For Link Time Optimization support llvm-devel: For ld64 -bitcode_bundle support uuid-devel: For ld64 -random_uuid support</p><blockquote><p>In clang there is no difference between cross-compilation and native compilation, so OSXCross can use a normal clang install for both. You can use either a clang installation you already have, or build your own from source.</p></blockquote><p>由于我们已经安装了系统clang了,因此不用手动再编译.</p><p>我们接下来直接使用clang 编译 cross toolchain, 执行 <code>./build.sh</code> :</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"> ~/repo/toolchain/osxcross on  master </span><span class="code-line">❯ ./build.sh </span><span class="code-line">found SDK version <span class="token number">13.1</span> at tarballs/MacOSX13.1.sdk.tar.xz </span><span class="code-line">verified at /home/ttys3/repo/rust/macos/osxcross/tarballs/MacOSX13.1.sdk.tar.xz </span><span class="code-line"> </span><span class="code-line">Building OSXCross toolchain, Version: <span class="token number">1.4</span> </span><span class="code-line"> </span><span class="code-line">macOS SDK Version: <span class="token number">13.1</span>, Target: darwin22.2 </span><span class="code-line">Minimum targeted macOS Version: <span class="token number">10.9</span> </span><span class="code-line">Tarball Directory: /home/ttys3/repo/rust/macos/osxcross/tarballs </span><span class="code-line">Build Directory: /home/ttys3/repo/rust/macos/osxcross/build </span><span class="code-line">Install Directory: /home/ttys3/repo/rust/macos/osxcross/target </span><span class="code-line">SDK Install Directory: /home/ttys3/repo/rust/macos/osxcross/target/SDK </span><span class="code-line"> </span><span class="code-line">Press enter to start building </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 或使用UNATTENDED=1跳过问题直接构建</span> </span><span class="code-line"><span class="token variable assign-left">UNATTENDED</span><span class="token operator">=</span><span class="token number">1</span> ./build.sh </span></code></pre></div><p>构建成功后会有类似如下提示:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">Do not forget to <span class="token function">add</span> </span><span class="code-line"> </span><span class="code-line">/home/ttys3/repo/rust/macos/osxcross/target/bin </span><span class="code-line"> </span><span class="code-line">to your <span class="token constant environment">PATH</span> variable. </span><span class="code-line"> </span><span class="code-line">All done<span class="token operator">!</span> Now you can use o32-clang<span class="token punctuation">(</span>++<span class="token punctuation">)</span> and o64-clang<span class="token punctuation">(</span>++<span class="token punctuation">)</span> like a normal compiler. </span><span class="code-line"> </span><span class="code-line">Example usage: </span><span class="code-line"> </span><span class="code-line">Example <span class="token number">1</span>: <span class="token variable assign-left">CC</span><span class="token operator">=</span>o32-clang ./configure <span class="token variable parameter">--host</span><span class="token operator">=</span>i386-apple-darwin22.2 </span><span class="code-line">Example <span class="token number">2</span>: <span class="token variable assign-left">CC</span><span class="token operator">=</span>i386-apple-darwin22.2-clang ./configure <span class="token variable parameter">--host</span><span class="token operator">=</span>i386-apple-darwin22.2 </span><span class="code-line">Example <span class="token number">3</span>: o64-clang <span class="token variable parameter">-Wall</span> test.c <span class="token variable parameter">-o</span> <span class="token class-name builtin">test</span> </span><span class="code-line">Example <span class="token number">4</span>: x86_64-apple-darwin22.2-strip <span class="token variable parameter">-x</span> <span class="token class-name builtin">test</span> </span><span class="code-line"> </span><span class="code-line"><span class="token operator">!</span><span class="token operator">!</span><span class="token operator">!</span> Use aarch64-apple-darwin22.2-* instead of arm64-* when dealing with Automake <span class="token operator">!</span><span class="token operator">!</span><span class="token operator">!</span> </span><span class="code-line"><span class="token operator">!</span><span class="token operator">!</span><span class="token operator">!</span> <span class="token variable assign-left">CC</span><span class="token operator">=</span>aarch64-apple-darwin22.2-clang ./configure <span class="token variable parameter">--host</span><span class="token operator">=</span>aarch64-apple-darwin22.2 <span class="token operator">!</span><span class="token operator">!</span><span class="token operator">!</span> </span><span class="code-line"><span class="token operator">!</span><span class="token operator">!</span><span class="token operator">!</span> <span class="token variable assign-left">CC</span><span class="token operator">=</span><span class="token string">&quot;aarch64-apple-darwin22.2-clang -arch arm64e&quot;</span> ./configure <span class="token variable parameter">--host</span><span class="token operator">=</span>aarch64-apple-darwin22.2 <span class="token operator">!</span><span class="token operator">!</span><span class="token operator">!</span> </span><span class="code-line"> </span><span class="code-line">Your SDK does not support i386 anymore. </span><span class="code-line">Use <span class="token operator">&lt;=</span> <span class="token number">10.13</span> SDK <span class="token keyword">if</span> you rely on i386 support. </span><span class="code-line"> </span><span class="code-line">Your SDK does not support libstdc++ anymore. </span><span class="code-line">Use <span class="token operator">&lt;=</span> <span class="token number">10.13</span> SDK <span class="token keyword">if</span> you rely on libstdc++ support. </span></code></pre></div><p>这里有关于32位支持和 libstdc++ 依赖的提示, 如果需要依赖这两个之一,就需要使用小于等于 10.13 的SDK</p><p>构建好的文件都在 <code>target</code> 目录下,直接放在这里显然不合适,我们把它移动到一个合适一点的地方, 比如 <code>/usr/local/darwin-ndk-x86_64</code>:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">mkdir</span> /usr/local/darwin-ndk-x86_64 </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">mv</span> target/* /usr/local/darwin-ndk-x86_64/ </span></code></pre></div><p>如果还需要使用gcc作为交叉编译器的话,还需要行 <code>./build_gcc.sh</code>, 不过这里我们是使用clang, 因此略过。</p><h3 id="tips"><a href="#tips" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>tips</h3><p>链接错误问题:</p><blockquote><p>x86_64-apple-darwin22.2-ld: error while loading shared libraries: libxar.so.1: cannot open shared object file: No such file or directory</p></blockquote><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">ls</span> <span class="token variable parameter">-l</span> /usr/local/darwin-ndk-x86_64/lib </span><span class="code-line">lrwxrwxrwx ttys3 ttys3 <span class="token number">15</span> B Wed Jan <span class="token number">27</span> <span class="token number">10</span>:46:58 <span class="token number">2021</span>  libtapi.so ⇒ libtapi.so.8svn </span><span class="code-line">.rw-r--r-- ttys3 ttys3 <span class="token number">3.2</span> MB Wed Jan <span class="token number">27</span> <span class="token number">10</span>:46:58 <span class="token number">2021</span>  libtapi.so.8svn </span><span class="code-line">.rw-r--r-- ttys3 ttys3 <span class="token number">205</span> KB Wed Jan <span class="token number">27</span> <span class="token number">10</span>:43:54 <span class="token number">2021</span>  libxar.a </span><span class="code-line">.rw-r--r-- ttys3 ttys3 <span class="token number">800</span> B Wed Jan <span class="token number">27</span> <span class="token number">10</span>:43:54 <span class="token number">2021</span>  libxar.la </span><span class="code-line">lrwxrwxrwx ttys3 ttys3 <span class="token number">11</span> B Wed Jan <span class="token number">27</span> <span class="token number">10</span>:43:54 <span class="token number">2021</span>  libxar.so ⇒ libxar.so.1 </span><span class="code-line">.rwxr-xr-x ttys3 ttys3 <span class="token number">142</span> KB Wed Jan <span class="token number">27</span> <span class="token number">10</span>:43:54 <span class="token number">2021</span>  libxar.so.1 </span></code></pre></div><p>解决:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token class-name builtin">echo</span> /usr/local/darwin-ndk-x86_64/lib <span class="token operator">|</span> <span class="token function">sudo</span> <span class="token function">tee</span> /etc/ld.so.conf.d/darwin.conf </span><span class="code-line"><span class="token function">sudo</span> ldconfig </span></code></pre></div><blockquote><p>ATTENTION:</p></blockquote><blockquote><p>OSXCross links libgcc and libstdc++ statically by default (this affects -foc-use-gcc-libstdc++ too). You can turn this behavior off with OSXCROSS_GCC_NO_STATIC_RUNTIME=1 (env).</p></blockquote><blockquote><p>The build also creates aliases *-g++-libc++ which link with the clang implementation of the C++ standard library instead of the GCC version. Don&#x27;t use these variants unless you know what you&#x27;re doing.</p></blockquote><h2 id="configuring-cargo"><a href="#configuring-cargo" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Configuring Cargo</h2><p>编辑 <code>.cargo/config</code>, 增加</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">target.x86_64-apple-darwin</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">linker</span> <span class="token punctuation">=</span> <span class="token string">&quot;/usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin22.2-clang&quot;</span> </span><span class="code-line"><span class="token key property">ar</span> <span class="token punctuation">=</span> <span class="token string">&quot;/usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin22.2-ar&quot;</span> </span></code></pre></div><p>这里很重要,尤其是 <code>linker</code>, 如果没有配置, cargo 默认只会使用 <code>cc</code>, 而不会使用 <code>clang</code>, 即使你 export 了 <code>CC=xxxxx</code>, 在最后link的时候会报错( 报错类似于 <a href="https://gist.github.com/Edu4rdSHL/49b8b52bac916d88e32861a817d5f9a5">https://gist.github.com/Edu4rdSHL/49b8b52bac916d88e32861a817d5f9a5</a> )</p><h2 id="building-the-project"><a href="#building-the-project" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Building the project</h2><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token variable assign-left"><span class="token constant environment">PATH</span></span><span class="token operator">=</span><span class="token string">&quot;/usr/local/darwin-ndk-x86_64/bin/:<span class="token constant environment">$PATH</span>&quot;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable assign-left">CC</span><span class="token operator">=</span>o64-clang <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable assign-left">CXX</span><span class="token operator">=</span>o64-clang++ <span class="token punctuation">\</span> </span><span class="code-line"><span class="token function">cargo</span> build <span class="token variable parameter">--target</span> x86_64-apple-darwin </span></code></pre></div><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">file</span> ./target/x86_64-apple-darwin/release/git-cz.darwin </span><span class="code-line">./target/x86_64-apple-darwin/release/git-cz.darwin: Mach-O <span class="token number">64</span>-bit x86_64 executable, flags:<span class="token operator">&lt;</span>NOUNDEFS<span class="token operator">|</span>DYLDLINK<span class="token operator">|</span>TWOLEVEL<span class="token operator">|</span>PIE<span class="token operator">|</span>HAS_TLV_DESCRIPTORS<span class="token operator">&gt;</span> </span></code></pre></div><p>OK, the binary: <a href="https://github.com/ttys3/git-cz/releases/download/v0.6.0/git-cz.darwin">https://github.com/ttys3/git-cz/releases/download/v0.6.0/git-cz.darwin</a></p><h2 id="misc"><a href="#misc" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Misc</h2><h3 id="o64-clang-and-x86_64-apple-darwin-clang"><a href="#o64-clang-and-x86_64-apple-darwin-clang" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>o64-clang and x86_64-apple-darwin*-clang</h3><p>link to the same wrapper: <code>x86_64-apple-darwin22.2-wrapper</code></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">ls</span> <span class="token variable parameter">-lh</span> /usr/local/darwin-ndk-x86_64/bin/o64-clang </span><span class="code-line">lrwxrwxrwx ttys3 ttys3 <span class="token number">31</span> B Sun Jan <span class="token number">24</span> <span class="token number">23</span>:43:35 <span class="token number">2021</span>  /usr/local/darwin-ndk-x86_64/bin/o64-clang ⇒ x86_64-apple-darwin22.2-wrapper </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">ls</span> <span class="token variable parameter">-lh</span> /usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin22.2-clang </span><span class="code-line">lrwxrwxrwx ttys3 ttys3 <span class="token number">31</span> B Sun Jan <span class="token number">24</span> <span class="token number">23</span>:43:35 <span class="token number">2021</span>  /usr/local/darwin-ndk-x86_64/bin/x86_64-apple-darwin22.2-clang ⇒ x86_64-apple-darwin22.2-wrapper </span></code></pre></div><p>check all wrapper been linked to:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">ls</span> <span class="token variable parameter">-l</span> /usr/local/darwin-ndk-x86_64/bin/* <span class="token operator">|</span> rg wrapper </span></code></pre></div><h3 id="building--sys-crates"><a href="#building--sys-crates" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Building *-sys crates</h3><p>带C绑定的一些lib(一般命名为<code>*-sys</code>, 如 libz-sys )如果要交叉编译,你还得设置CC和CXX环境变量。 这样能编译成功了,但是最后链接阶段可能失败,原因是链接了错误的库.</p><p>有些库提供了环境变量可以方便使用交叉编译工具重新编译,比如 <a href="https://github.com/rust-lang/libz-sys/blob/master/build.rs#L25">https://github.com/rust-lang/libz-sys/blob/master/build.rs#L25</a></p><p>如果设定了<code>LIBZ_SYS_STATIC=1</code>, 则会编译一个静态版本的, 由于我们指定了 CC 和 CXX 都是Mac的,因此可以成功链接。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token variable assign-left"><span class="token constant environment">PATH</span></span><span class="token operator">=</span><span class="token string">&quot;/usr/local/darwin-ndk-x86_64/bin/:<span class="token constant environment">$PATH</span>&quot;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable assign-left">CC</span><span class="token operator">=</span>o64-clang <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable assign-left">CXX</span><span class="token operator">=</span>o64-clang++ <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable assign-left">LIBZ_SYS_STATIC</span><span class="token operator">=</span><span class="token number">1</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token function">cargo</span> build <span class="token variable parameter">--target</span> x86_64-apple-darwin </span></code></pre></div><h3 id="about-xip-files"><a href="#about-xip-files" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>About xip files</h3><blockquote><p>Unpacking XIP files on Linux</p></blockquote><ol><li>Install xar from <a href="https://mackyle.github.io/xar/">https://mackyle.github.io/xar/</a> (or my fork <a href="https://github.com/ttys3/xar">https://github.com/ttys3/xar</a> )</li><li>Install pbzx from <a href="https://github.com/NiklasRosenstein/pbzx">https://github.com/NiklasRosenstein/pbzx</a> (or my fork <a href="https://github.com/ttys3/pbzx/">https://github.com/ttys3/pbzx/</a> ) (use <code>gcc -llzma -lxar -I /usr/local/include pbzx.c -o pbzx</code> and copy the binary into your PATH)</li><li>use <code>xar -xf XIP_FILE -C /path/to/extract/to</code></li><li>Change to the directory where you extracted the file.</li><li>Use <code>pbzx -n Content | cpio -i</code> to extract the contents.</li></ol><p>ref: <a href="https://gist.github.com/phracker/1944ce190e01963c550566b749bd2b54">https://gist.github.com/phracker/1944ce190e01963c550566b749bd2b54</a></p><p>不过在这里,我们并不需要按上面的步骤手动提取,OSXCross 都已经有自动解包和打包脚本,很全.</p><p>xar 这个库, 原版已经很多年没人维护了, 所以,这里其实作者用了它自己的 fork 版: <a href="https://github.com/tpoechtrager/xar">https://github.com/tpoechtrager/xar</a></p><p>老灯也 fork 了一个, 增加了 ArchLinux <code>PKGBUILD</code> <a href="https://github.com/ttys3/xar">https://github.com/ttys3/xar</a></p><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://www.reddit.com/r/rust/comments/6rxoty/tutorial_cross_compiling_from_linux_for_osx/">https://www.reddit.com/r/rust/comments/6rxoty/tutorial_cross_compiling_from_linux_for_osx/</a></p><p><a href="https://wapl.es/rust/2019/02/17/rust-cross-compile-linux-to-macos.html">https://wapl.es/rust/2019/02/17/rust-cross-compile-linux-to-macos.html</a></p><p><a href="https://github.com/tpoechtrager/osxcross">https://github.com/tpoechtrager/osxcross</a></p><p><a href="https://github.com/rust-lang/backtrace-rs/issues/240">https://github.com/rust-lang/backtrace-rs/issues/240</a></p><p><a href="https://gist.github.com/Edu4rdSHL/49b8b52bac916d88e32861a817d5f9a5">https://gist.github.com/Edu4rdSHL/49b8b52bac916d88e32861a817d5f9a5</a></p><p><a href="https://john-millikin.com/notes-on-cross-compiling-rust">https://john-millikin.com/notes-on-cross-compiling-rust</a></p><p><a href="https://github.com/ttys3/xar/blob/master/xar.md">https://github.com/ttys3/xar/blob/master/xar.md</a></p><p><a href="https://github.com/rust-embedded/cross">https://github.com/rust-embedded/cross</a></p><p><a href="https://github.com/etrombly/gtk_osx_cross/blob/master/README.md">https://github.com/etrombly/gtk_osx_cross/blob/master/README.md</a></p><p><a href="https://rust-lang.github.io/rustup-components-history/x86_64-apple-darwin.html">https://rust-lang.github.io/rustup-components-history/x86_64-apple-darwin.html</a></p> Sun, 24 Jan 2021 16:53:36 GMT ttyS3 rustosxcompilecross-compilelinux https://ttys3.dev/blog/tmux-24bit-true-color-support Tmux 24bit True Color Support https://ttys3.dev/blog/tmux-24bit-true-color-support <h2 id="如何检测24bit颜色支持"><a href="#如何检测24bit颜色支持" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何检测24bit颜色支持</h2><p>以前一直没怎么注意这个问题,直到这次我自己基于base16框架做了一个Jetbrains Gruvbox soft black 配色的 port ,发现同一个代码,在Gnome Terminal 和 tmux 下显示效果差异很大。</p><p>GNOME Terminal下显示正常:</p><div><img alt="gnome-terminal-vim-256-color-test-ok.png" src="https://ttys3.dev/static/assets/gnome-terminal-vim-256-color-test-ok-2V4JWSUV.png" width="1805" height="811"/></div><p>tmux 下显示的颜色不对:</p><div><img alt="tmux-vim-no-256.png" src="https://ttys3.dev/static/assets/tmux-vim-no-256-4RQHGOFV.png" width="1920" height="813"/></div><p>于是我突然想起来,256 color 的支持问题.</p><p>事实上tmux官方仓库里有两个很好的工具,用于检测256 color 是否被支持:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-sSfL</span> https://github.com/tmux/tmux/raw/master/tools/24-bit-color.sh <span class="token operator">|</span> <span class="token function">sh</span> </span></code></pre></div><p>perl 脚本那个不太容易看看出来:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-sSfL</span> https://github.com/tmux/tmux/raw/master/tools/256colors.pl <span class="token operator">|</span> perl </span></code></pre></div><p>这两个脚本我这里也存了一份:</p><p><a href="24-bit-color.sh">24-bit-color.sh</a></p><p><a href="256colors.pl">256colors.pl</a></p><p>24bit color:</p><div><img alt="tmux-24bit-true-color-ok.png" src="https://ttys3.dev/static/assets/tmux-24bit-true-color-ok-AWBP6KX6.png" width="2343" height="994"/></div><div><img alt="tmux-8bit-color-alacritty.png" src="https://ttys3.dev/static/assets/tmux-8bit-color-alacritty-GX5XHFMR.png" width="2327" height="956"/></div><p><code>24-bit-color.sh</code> 的识别度非常好,可以下载回来作为常规检测工具使用。</p><p>另外还有一段awk代码也不错:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">awk</span> <span class="token string">&#x27;BEGIN{ </span></span><span class="code-line"><span class="token string"> s=&quot;/\\/\\/\\/\\/\\&quot;; s=s s s s s s s s; </span></span><span class="code-line"><span class="token string"> for (colnum = 0; colnum&lt;77; colnum++) { </span></span><span class="code-line"><span class="token string"> r = 255-(colnum*255/76); </span></span><span class="code-line"><span class="token string"> g = (colnum*510/76); </span></span><span class="code-line"><span class="token string"> b = (colnum*255/76); </span></span><span class="code-line"><span class="token string"> if (g&gt;255) g = 510-g; </span></span><span class="code-line"><span class="token string"> printf &quot;\033[48;2;%d;%d;%dm&quot;, r,g,b; </span></span><span class="code-line"><span class="token string"> printf &quot;\033[38;2;%d;%d;%dm&quot;, 255-r,255-g,255-b; </span></span><span class="code-line"><span class="token string"> printf &quot;%s\033[0m&quot;, substr(s,colnum+1,1); </span></span><span class="code-line"><span class="token string"> } </span></span><span class="code-line"><span class="token string"> printf &quot;\n&quot;; </span></span><span class="code-line"><span class="token string">}&#x27;</span> </span></code></pre></div><h2 id="tmux-配置"><a href="#tmux-配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>tmux 配置</h2><blockquote><p>tmux must be told that the terminal outside supports RGB colour. This is done by specifying the RGB or Tc terminfo(5) flags. RGB is the official flag, Tc is a tmux extension. With tmux 3.2 and later this can be added with the terminal-features option: <code>set -as terminal-features &quot;,gnome*:RGB&quot;</code> Or for any tmux version the terminal-overrides option: <code>set -as terminal-overrides &quot;,gnome*:Tc&quot;</code></p></blockquote><p>编辑 <code>.tmux.conf</code>, 增加两行(注意下面,一个是适用于3.2的,一个是适用于3.1的):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">set</span> <span class="token variable parameter">-g</span> default-terminal <span class="token string">&quot;tmux-256color&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># tmux 3.2之后</span> </span><span class="code-line"><span class="token builtin class-name">set</span> <span class="token variable parameter">-as</span> terminal-features <span class="token string">&quot;,xterm-256color:RGB&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># tmux 3.1</span> </span><span class="code-line"><span class="token builtin class-name">set</span> <span class="token variable parameter">-as</span> terminal-overrides <span class="token string">&quot;,xterm-256color:RGB&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 如果tmux只在gnome terminal里打开</span> </span><span class="code-line"><span class="token comment"># set -as terminal-features &quot;,gnome*:RGB&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 如果tmux只在alacritty里打开</span> </span><span class="code-line"><span class="token comment"># set -ag terminal-features &quot;,alacritty:RGB&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 兼容方案</span> </span><span class="code-line"><span class="token comment"># set -as terminal-overrides &quot;,xterm-256color:RGB&quot;</span> </span></code></pre></div><blockquote><p>terminal-overrides applies to the outside <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi><mi>E</mi><mi>R</mi><mi>M</mi><mi mathvariant="normal">.</mi><mi>I</mi><mi>t</mi><mi>b</mi><mi>a</mi><mi>s</mi><mi>i</mi><mi>c</mi><mi>a</mi><mi>l</mi><mi>l</mi><mi>y</mi><mi>s</mi><mi>a</mi><mi>y</mi><mi>s</mi><mo>:</mo><mi>W</mi><mi>h</mi><mi>e</mi><mi>n</mi><mi>s</mi><mi>t</mi><mi>a</mi><mi>r</mi><mi>t</mi><mi>i</mi><mi>n</mi><mi>g</mi><mi>t</mi><mi>m</mi><mi>u</mi><mi>x</mi><mi>i</mi><mi>n</mi><mi>a</mi><mi>s</mi><mi>h</mi><mi>e</mi><mi>l</mi><mi>l</mi><mi>t</mi><mi>h</mi><mi>a</mi><mi>t</mi><mi>h</mi><mi>a</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">TERM. It basically says: When starting tmux in a shell that has </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:.8889em;vertical-align:-.1944em"></span><span class="mord mathnormal" style="margin-right:.10903em">TERM</span><span class="mord">.</span><span class="mord mathnormal" style="margin-right:.07847em">I</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ba</span><span class="mord mathnormal">s</span><span class="mord mathnormal">i</span><span class="mord mathnormal">c</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:.01968em">ll</span><span class="mord mathnormal">ys</span><span class="mord mathnormal">a</span><span class="mord mathnormal">ys</span><span class="mspace" style="margin-right:.2778em"></span><span class="mrel">:</span><span class="mspace" style="margin-right:.2778em"></span></span><span class="base"><span class="strut" style="height:.8889em;vertical-align:-.1944em"></span><span class="mord mathnormal">Wh</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:.02778em">r</span><span class="mord mathnormal">t</span><span class="mord mathnormal">in</span><span class="mord mathnormal" style="margin-right:.03588em">g</span><span class="mord mathnormal">t</span><span class="mord mathnormal">m</span><span class="mord mathnormal">ux</span><span class="mord mathnormal">ina</span><span class="mord mathnormal">s</span><span class="mord mathnormal">h</span><span class="mord mathnormal">e</span><span class="mord mathnormal">llt</span><span class="mord mathnormal">ha</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ha</span><span class="mord mathnormal">s</span></span></span></span></span>TERM set to xterm-256color, add the Tc capability to tmux&#x27;s internal image of tmux-256color to signalize it to use true colors.</p></blockquote><h2 id="oh-my-tmux-配置"><a href="#oh-my-tmux-配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>oh my tmux 配置</h2><p><a href="https://github.com/gpakosz/.tmux">oh my tmux</a> 默认已经内置支持了,但是默认是关闭的。</p><p>只需要编辑 <code>.tmux.conf.local</code>, 将<code>tmux_conf_theme_24b_colour=true</code>修改为<code>true</code></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token variable assign-left">tmux_conf_theme_24b_colour</span><span class="token operator">=</span>true </span></code></pre></div><p>它最终会执行:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"> </span><span class="code-line">run <span class="token string">&#x27;cut -c3- ~/.tmux.conf | sh -s _apply_configuration&#x27;</span> </span><span class="code-line"> </span></code></pre></div><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># _apply_configuration -&gt; _apply_overrides</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function function-name">_apply_overrides</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token variable assign-left">tmux_conf_theme_24b_colour</span><span class="token operator">=</span><span class="token variable">${tmux_conf_theme_24b_colour<span class="token operator">:-</span>false}</span> </span><span class="code-line"> <span class="token keyword">if</span> _is_enabled <span class="token string">&quot;<span class="token variable">$tmux_conf_theme_24b_colour</span>&quot;</span><span class="token punctuation">;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token keyword">case</span> <span class="token string">&quot;<span class="token constant environment">$TERM</span>&quot;</span> <span class="token keyword">in</span> </span><span class="code-line"> screen-*<span class="token operator">|</span>tmux-*<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">;</span><span class="token punctuation">;</span> </span><span class="code-line"> *<span class="token punctuation">)</span> </span><span class="code-line"> tmux set-option <span class="token variable parameter">-ga</span> terminal-overrides <span class="token string">&quot;,*256col*:Tc&quot;</span> </span><span class="code-line"> <span class="token punctuation">;</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">esac</span> </span><span class="code-line"> <span class="token keyword">fi</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 因此实际上它是执行的</span> </span><span class="code-line"><span class="token comment"># tmux set-option -ga terminal-overrides &quot;,*256col*:Tc&quot;</span> </span></code></pre></div><h2 id="alacritty-支持"><a href="#alacritty-支持" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Alacritty 支持</h2><p>除非我们在tmux配置了<code>set -ag terminal-overrides &quot;,alacritty:RGB&quot;</code> (tmux 3.1) 或<code>set -ag terminal-features &quot;,alacritty:RGB&quot;</code> (tmux 3.2), 否则,默认情况下, 我们在Alacritty里运行tmux, tmux还是不能支持24bit color.</p><p>但是,如果设置<code>set -ag terminal-overrides &quot;,alacritty:RGB&quot;</code>, 当tmux跑在 Gnome Terminal 下时,又失去24bit color了。</p><p>因此,为了兼容,我们需要修改Alacrity 的配置:</p><div class="relative"><pre><code class="code-highlight language-yaml"><span class="code-line"><span class="token comment"># Any items in the `env` entry below will be added as</span> </span><span class="code-line"><span class="token comment"># environment variables. Some entries may override variables</span> </span><span class="code-line"><span class="token comment"># set by alacritty itself.</span> </span><span class="code-line"><span class="token atrule key">env</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token comment"># TERM variable</span> </span><span class="code-line"> <span class="token comment">#</span> </span><span class="code-line"> <span class="token comment"># This value is used to set the `$TERM` environment variable for</span> </span><span class="code-line"> <span class="token comment"># each instance of Alacritty. If it is not present, alacritty will</span> </span><span class="code-line"> <span class="token comment"># check the local terminfo database and use `alacritty` if it is</span> </span><span class="code-line"> <span class="token comment"># available, otherwise `xterm-256color` is used.</span> </span><span class="code-line"> <span class="token comment"># TERM: alacritty</span> </span><span class="code-line"> <span class="token atrule key">TERM</span><span class="token punctuation">:</span> xterm<span class="token punctuation">-</span>256color </span></code></pre></div><p>它的<code>TERM</code> 默认值是 <code>alacritty</code>, 而当前tmux并不能识别它是不是支持256color, 因此,我们需要把它设置成兼容 <code>xterm-256color</code></p><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://github.com/tmux/tmux/issues/1246#issuecomment-493454336">https://github.com/tmux/tmux/issues/1246#issuecomment-493454336</a></p><p><a href="https://jdhao.github.io/2018/10/19/tmux_nvim_true_color/">https://jdhao.github.io/2018/10/19/tmux_nvim_true_color/</a></p><p><a href="https://github.com/tmux/tmux/wiki/FAQ#how-do-i-use-rgb-colour">https://github.com/tmux/tmux/wiki/FAQ#how-do-i-use-rgb-colour</a></p><p><a href="https://stackoverflow.com/q/15375992/6064933">https://stackoverflow.com/q/15375992/6064933</a></p><p><a href="https://github.com/neovim/neovim/issues/7353#issuecomment-334279343">Good explanation about what terminal-overrides does.</a></p><p><a href="https://stackoverflow.com/q/41783367/6064933">https://stackoverflow.com/q/41783367/6064933</a></p><p><a href="https://www.reddit.com/r/neovim/comments/825dj7/the_endless_litany_of_tmux_and_nvim_color_problems/">https://www.reddit.com/r/neovim/comments/825dj7/the_endless_litany_of_tmux_and_nvim_color_problems/</a></p><p><a href="https://stackoverflow.com/a/40482330/6064933">Why you should not set TERM inside shell config file</a></p><p><a href="https://unix.stackexchange.com/q/139082/221410">You should not set TERM inside shell config file.</a></p> Sun, 10 Jan 2021 10:43:52 GMT ttyS3 tmuxterminal https://ttys3.dev/blog/nvim-and-rime-esc-auto-switch Nvim and Rime Esc Auto Switch https://ttys3.dev/blog/nvim-and-rime-esc-auto-switch <h2 id="前提"><a href="#前提" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>前提</h2><p>简单描述下自动切换的行为:</p><blockquote><p>nvim记住最近一次插入模式时的输入法(可能是英文,也可能是中文) esc回到正常模式时,插件自动将系统输入法切换到英文状态 重新回到插入模式时, nvim自动切回上次插入模式时的输入法.</p></blockquote><p>环境: ibus + ibus-rime + neovim</p><p>当前我的rime配置是有自带ascii mode的,也就是配置了输入中文时简单地按下<code>shift</code>就会切换到英文输入模式。</p><p>然而这个ascii mode 外部是无法感知的,也就是只有rime 自己知道,ibus是不知道的。</p><p>之前用fcitx 是没有这个问题的,fcitx-remote 配合vim插件<a href="https://github.com/lilydjwg/fcitx.vim">fcitx.vim</a>可以非常方便地进行切换。</p><p>当前大部分对于ibus控制的插件实现都是无法直接控制到rime的。</p><p>因此,我当前的rime配置需要做一些调整。</p><blockquote><p>如果使用的是mac或windows版的rime, 那么,其实前端这边是有支持<code>vim_mode</code>的, 见 <a href="https://github.com/rime/squirrel/issues/124">https://github.com/rime/squirrel/issues/124</a> 和 <a href="https://github.com/rime/weasel/issues/12">https://github.com/rime/weasel/issues/12</a> 但是这个只是在前端, librime是没有这个选项的。 见 <a href="https://github.com/rime/librime/issues/295">https://github.com/rime/librime/issues/295</a></p></blockquote><p>由于我的主要使用场景是Linux, 因此rime自带的<code>vim_mode</code>方案不可用。</p><p>另外,通过配置rime使用esc来toggle ascii_mode的方案也不太好:</p><div class="relative"><pre><code class="language-yaml code-highlight"><span class="code-line"><span class="token atrule key">key_binder/bindings</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span> <span class="token atrule key">when</span><span class="token punctuation">:</span> always<span class="token punctuation">,</span> <span class="token atrule key">accept</span><span class="token punctuation">:</span> Escape<span class="token punctuation">,</span> <span class="token atrule key">toggle</span><span class="token punctuation">:</span> ascii_mode<span class="token punctuation">}</span> </span></code></pre></div><blockquote><p>这样就可以使用 Esc 键切换为英文模式,但是这样有一个弊端,必须得先按一次 Esc 切换为英文后,再按一次 Esc 切换为普通模式</p></blockquote><p>我当前的rime配置是:</p><div class="relative"><pre><code class="language-yaml code-highlight"><span class="code-line"><span class="token comment"># @see https://github.com/rime/home/wiki/CustomizationGuide</span> </span><span class="code-line"><span class="token atrule key">customization</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">generator</span><span class="token punctuation">:</span> <span class="token string">&quot;Rime::SwitcherSettings&quot;</span> </span><span class="code-line"> <span class="token atrule key">modified_time</span><span class="token punctuation">:</span> <span class="token string">&quot;Sat Dec 31 12:11:20 2016&quot;</span> </span><span class="code-line"><span class="token atrule key">patch</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">schema_list</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">schema</span><span class="token punctuation">:</span> wubi86<span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">schema</span><span class="token punctuation">:</span> wubi_pinyin<span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">&quot;key_binder/bindings&quot;</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span> <span class="token atrule key">when</span><span class="token punctuation">:</span> composing<span class="token punctuation">,</span> <span class="token atrule key">accept</span><span class="token punctuation">:</span> Return<span class="token punctuation">,</span> <span class="token atrule key">send</span><span class="token punctuation">:</span> Escape <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span> <span class="token atrule key">when</span><span class="token punctuation">:</span> has_menu<span class="token punctuation">,</span> <span class="token atrule key">accept</span><span class="token punctuation">:</span> semicolon<span class="token punctuation">,</span> <span class="token atrule key">send</span><span class="token punctuation">:</span> <span class="token number">2</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span> <span class="token atrule key">when</span><span class="token punctuation">:</span> has_menu<span class="token punctuation">,</span> <span class="token atrule key">accept</span><span class="token punctuation">:</span> apostrophe<span class="token punctuation">,</span> <span class="token atrule key">send</span><span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">&quot;ascii_composer: good_old_caps_lock&quot;</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> </span><span class="code-line"> <span class="token atrule key">&quot;ascii_composer/switch_key&quot;</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">Caps_Lock</span><span class="token punctuation">:</span> commit_code </span><span class="code-line"> <span class="token atrule key">Control_L</span><span class="token punctuation">:</span> noop </span><span class="code-line"> <span class="token atrule key">Control_R</span><span class="token punctuation">:</span> noop </span><span class="code-line"> <span class="token atrule key">Shift_L</span><span class="token punctuation">:</span> commit_code </span><span class="code-line"> <span class="token atrule key">Shift_R</span><span class="token punctuation">:</span> commit_code </span><span class="code-line"> <span class="token atrule key">&quot;switcher/hotkeys&quot;</span><span class="token punctuation">:</span> <span class="token comment"># 這個列表裏每項定義一個快捷鍵,使哪個都中</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token string">&quot;Control+grave&quot;</span> <span class="token comment"># 你看寫法並不是 Ctrl+` 而是與 IBus 一致的表示法</span> </span><span class="code-line"> <span class="token comment">#- F4 # disable default F4 map, leave it for Neovim</span> </span><span class="code-line"> <span class="token atrule key">switches</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> ascii_mode </span><span class="code-line"> <span class="token atrule key">reset</span><span class="token punctuation">:</span> <span class="token number">1</span> </span><span class="code-line"> <span class="token atrule key">states</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> 中文<span class="token punctuation">,</span> 西文 <span class="token punctuation">]</span> </span></code></pre></div><p>也就是,在输入时,随便输入左/右shift 或 caps lock键,都可以在中文输入模式和ascii 输入模式之间快速切换。 这期间对于系统或ibus来说,是没有切换输入法的。</p><p>如果要在Vim里面控制这种切换,那么,只能控制到ibus层面, 要做哪些改变呢?</p><h2 id="切换rime的ascii-switch-默认状态"><a href="#切换rime的ascii-switch-默认状态" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>切换rime的ascii switch 默认状态</h2><p><code>reset</code> 为<code>1</code>时的问题: 比如:vim插入模式:rime中文输入 -&gt; vim普通模式(输入法从rime切成了en)-&gt; 再切回插入模式,此时 输入法还是英文,我们得再按一次shift切换成中文。</p><p>因此, ascii_mode <code>reset</code> 为<code>1</code> 时适合将rime作为默认输入法使用。</p><p>将<code>reset</code>从<code>1</code> 修改成<code>0</code>, 即可让rime从别的输入法切回时,总是中文输入状态,而不是总是英文(ascii_mode)</p><p>同时,要从rime切换到英文输入法,我们要确保有一个英文输入法添加到ibus.</p><p>可以通过<code>ibus-setup</code>检查你的配置.</p><p>因此, ascii_mode <code>reset</code> 为<code>0</code> 时适合将rime作为第二输入法使用,首选输入法应该是英文。 要记得在GNOME3系统配置里的<code>Input Source</code> 那里,将<code>English(US)</code>排到rime前面来。 毕竟,我们敲代码比较多,英文在任何时候应该是首选的。</p><div class="relative"><pre><code class="language-yaml code-highlight"><span class="code-line"><span class="token atrule key">customization</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">generator</span><span class="token punctuation">:</span> <span class="token string">&quot;Rime::SwitcherSettings&quot;</span> </span><span class="code-line"> <span class="token atrule key">modified_time</span><span class="token punctuation">:</span> <span class="token string">&quot;Sat Dec 31 12:11:20 2016&quot;</span> </span><span class="code-line"><span class="token atrule key">patch</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">schema_list</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">schema</span><span class="token punctuation">:</span> wubi86<span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token atrule key">schema</span><span class="token punctuation">:</span> wubi_pinyin<span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">&quot;key_binder/bindings&quot;</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span> <span class="token atrule key">when</span><span class="token punctuation">:</span> composing<span class="token punctuation">,</span> <span class="token atrule key">accept</span><span class="token punctuation">:</span> Return<span class="token punctuation">,</span> <span class="token atrule key">send</span><span class="token punctuation">:</span> Escape <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span> <span class="token atrule key">when</span><span class="token punctuation">:</span> has_menu<span class="token punctuation">,</span> <span class="token atrule key">accept</span><span class="token punctuation">:</span> semicolon<span class="token punctuation">,</span> <span class="token atrule key">send</span><span class="token punctuation">:</span> <span class="token number">2</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token punctuation">{</span> <span class="token atrule key">when</span><span class="token punctuation">:</span> has_menu<span class="token punctuation">,</span> <span class="token atrule key">accept</span><span class="token punctuation">:</span> apostrophe<span class="token punctuation">,</span> <span class="token atrule key">send</span><span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">&quot;ascii_composer: good_old_caps_lock&quot;</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> </span><span class="code-line"> <span class="token atrule key">&quot;ascii_composer/switch_key&quot;</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">Caps_Lock</span><span class="token punctuation">:</span> commit_code </span><span class="code-line"> <span class="token atrule key">Control_L</span><span class="token punctuation">:</span> noop </span><span class="code-line"> <span class="token atrule key">Control_R</span><span class="token punctuation">:</span> noop </span><span class="code-line"> <span class="token atrule key">Shift_L</span><span class="token punctuation">:</span> commit_code </span><span class="code-line"> <span class="token atrule key">Shift_R</span><span class="token punctuation">:</span> commit_code </span><span class="code-line"> <span class="token atrule key">&quot;switcher/hotkeys&quot;</span><span class="token punctuation">:</span> <span class="token comment"># 這個列表裏每項定義一個快捷鍵,使哪個都中</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token string">&quot;Control+grave&quot;</span> <span class="token comment"># 你看寫法並不是 Ctrl+` 而是與 IBus 一致的表示法</span> </span><span class="code-line"> <span class="token comment">#- F4 # disable default F4 map, leave it for Neovim</span> </span><span class="code-line"> <span class="token atrule key">switches</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> ascii_mode </span><span class="code-line"> <span class="token atrule key">reset</span><span class="token punctuation">:</span> <span class="token number">0</span> </span><span class="code-line"> <span class="token atrule key">states</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> 中文<span class="token punctuation">,</span> 西文 <span class="token punctuation">]</span> </span></code></pre></div><p>gnome3 默认的输入法切换快捷键是: <code>super + space</code>, 短按可快捷切换,长按还能在屏正中overlay显示切换的输入法。</p><h2 id="安装配置合适的nvim支持插件"><a href="#安装配置合适的nvim支持插件" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装配置合适的nvim支持插件</h2><h3 id="vim-xkbswitch"><a href="#vim-xkbswitch" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>vim-xkbswitch</h3><p><a href="https://github.com/lyokha/vim-xkbswitch">vim-xkbswitch</a></p><p><code>https://github.com/lyokha/vim-xkbswitch</code></p><p>好处: 跨平台支持 Unix: <a href="http://github.com/ierton/xkb-switch">http://github.com/ierton/xkb-switch</a> <a href="https://github.com/lyokha/g3kb-switch">https://github.com/lyokha/g3kb-switch</a>) 原作者新项目 lyokha/g3kb-switch 解决了 Linux(GNOME) 下的切换</p><p>Win: <a href="http://github.com/DeXP/xkb-switch-win">http://github.com/DeXP/xkb-switch-win</a></p><p>OSX: <a href="http://github.com/myshov/xkbswitch-macosx">http://github.com/myshov/xkbswitch-macosx</a> , <a href="http://github.com/vovkasm/input-source-switcher">http://github.com/vovkasm/input-source-switcher</a></p><h3 id="vim-ibus"><a href="#vim-ibus" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>vim-ibus</h3><p><a href="https://github.com/h-youhei/vim-ibus">vim-ibus</a></p><p><code>https://github.com/h-youhei/vim-ibus</code>:</p><p>实际上它是直接使用的<code>ibus engine</code>来切换输入法, 在 GNOME 3 上切换输入法后,右上角状态栏图标并不会自动更新, fork 版本 <a href="https://github.com/zhmars/vim-ibus">zhmars/vim-ibus</a>简单修复了这个问题</p><p>使用<code>ibus list-engine</code>可以列出当前可用的engine, 但是实际上我们只会切到一个,那就是<code>xkb:us::eng</code></p><h3 id="vim-ibus-sw"><a href="#vim-ibus-sw" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>vim-ibus-sw</h3><p><a href="https://github.com/kevinhwang91/vim-ibus-sw">vim-ibus-sw</a></p><p><code>https://github.com/kevinhwang91/vim-ibus-sw</code></p><p>这个其实和h-youhei/vim-ibus 类似,只是更加智能,在GNOME3环境下,它会自动使用dbus通知的方式, 这样可以解决图片没有变的问题,在非GNOME3环境下,它同样会回退到 <code>ibus engine</code> 命令的方式。</p><p>由于老灯主要使用场景为Linux, 因此最终选择了 <code>kevinhwang91/vim-ibus-sw</code></p><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p>vim可不可以实现在在normal模式或者visual模式下自动改输入法为英文呢 <a href="https://www.zhihu.com/question/25744174">https://www.zhihu.com/question/25744174</a></p><p><a href="https://jiz4oh.com/2020/10/vim-fast-esc/">vim 中使用 esc 切换英文输入</a></p> Sun, 10 Jan 2021 07:58:02 GMT ttyS3 nvimrimeinput-methodcjk https://ttys3.dev/blog/luarocks-install-and-setup LuaRocks安装配置 https://ttys3.dev/blog/luarocks-install-and-setup <p>其实我安装 lua5.1 只是为了方便兼容 neovim 和 luajit, 这两货目前都只支持lua 5.1</p><p>其实根本原因还是在于 luajit 多年没更新(如果我没记错,现在已经2021年了,luajit最后一次发版还是2017年?),没有兼容最新版本的lua 5.4 。</p><p>而 neovim 实际是因为依赖luajit 才导致依赖 lua 5.1的,也是没办法了.</p><h2 id="初战翻车"><a href="#初战翻车" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>初战翻车</h2><p>环境说明: 操作系统是 Fedora 33, 默认的 <code>lua</code>包是 lua 5.4版本的, <code>luarocks</code> 也是从包管理器dnf直接安装的.</p><p><code>luarocks install --local fzy</code> 失败:</p><blockquote><p>Error: Failed finding Lua header files. You may need to install them or configure <code>LUA_INCDIR</code>.</p></blockquote><p>为了方式与luajit lua5.1 配合工作,同时避免包管理问题, 还是卸载系统的 luarocks, 自己编译安装吧.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">rpm</span> <span class="token parameter variable">-evh</span> luarocks </span></code></pre></div><p>然后,我们不要用Fedora 33系统自带的luarocks, 它的默认luarocks system配置是 lua 5.4的.</p><h3 id="fedora安装lua51和luajit"><a href="#fedora安装lua51和luajit" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Fedora安装lua5.1和luajit</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># compat-lua is lua5.1</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> compat-lua compat-lua-libs compat-lua-devel lua-filesystem-compat lua-socket-compat lua5.1-compat53 <span class="token punctuation">\</span> </span><span class="code-line">lua5.1-luv-devel lua5.1-http lua5.1-lpeg lua5.1-luaossl <span class="token punctuation">\</span> </span><span class="code-line">lua5.1-mmdb lua5.1-mpack lua5.1-psl lua5.1-sec lua5.1-basexx lua5.1-binaryheap lua5.1-bitop <span class="token punctuation">\</span> </span><span class="code-line">luajit </span></code></pre></div><h3 id="ubuntu2010安装lua51和luajit"><a href="#ubuntu2010安装lua51和luajit" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Ubuntu20.10安装lua5.1和luajit</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> libluajit-5.1-dev liblua5.1-0-dev </span></code></pre></div><h2 id="编译安装"><a href="#编译安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>编译安装</h2><p>当前最新版本的LuaRocks 版本为 3.5.0, 可以去 <a href="https://luarocks.github.io/luarocks/releases/">https://luarocks.github.io/luarocks/releases/</a> 查看。</p><p>Fedora 33 下可以用 <code>--with-lua-include=/usr/include/lua-5.1/</code>, 而这个路径在 Ubuntu 20.10 下面是 <code>/usr/include/lua5.1</code>, 因此还是不要加<code>--with-lua-include</code> 参数为好,让它自动查找,我们只需要指定 <code>--lua-version=5.1</code> 即可.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">curl</span> <span class="token parameter variable">-LZO</span> https://luarocks.org/releases/luarocks-3.5.0.tar.gz </span><span class="code-line"><span class="token function">tar</span> xvzpf luarocks-3.5.0.tar.gz </span><span class="code-line"><span class="token builtin class-name">cd</span> luarocks-3.5.0 </span><span class="code-line"> </span><span class="code-line">❯ ./configure --lua-version<span class="token operator">=</span><span class="token number">5.1</span> </span><span class="code-line"> </span><span class="code-line">Configuring LuaRocks version <span class="token number">3.5</span>.0<span class="token punctuation">..</span>. </span><span class="code-line"> </span><span class="code-line">Lua version detected: <span class="token number">5.1</span> </span><span class="code-line">Lua interpreter found: /usr/bin/lua-5.1 </span><span class="code-line">lua.h found: /usr/include/lua-5.1/lua.h </span><span class="code-line"><span class="token function">unzip</span> found <span class="token keyword">in</span> <span class="token constant environment">PATH</span><span class="token builtin class-name">:</span> /usr/bin </span><span class="code-line"> </span><span class="code-line">Done configuring. </span><span class="code-line"> </span><span class="code-line">LuaRocks will be installed at<span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span>: /usr/local </span><span class="code-line">LuaRocks will <span class="token function">install</span> rocks at<span class="token punctuation">..</span><span class="token punctuation">..</span>.: /usr/local </span><span class="code-line">LuaRocks configuration directory<span class="token punctuation">..</span>.: /usr/local/etc/luarocks </span><span class="code-line">Using Lua from<span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span>.: /usr </span><span class="code-line"> </span><span class="code-line">* Type <span class="token function">make</span> and <span class="token function">make</span> install: </span><span class="code-line"> to <span class="token function">install</span> to /usr/local as usual. </span><span class="code-line">* Type <span class="token function">make</span> bootstrap: </span><span class="code-line"> to <span class="token function">install</span> LuaRocks into /usr/local as a rock. </span></code></pre></div><p>可以看到,配置完后luarocks提示我们,有两种安装方式. 到底用哪一种呢?</p><p>万能的stackoverflow 很快给了我们答案:</p><blockquote><p>Should Icompile luarocks &#x27;as usual&#x27; or as a &#x27;rock&#x27;?</p></blockquote><blockquote><p>As you can see from the <a href="https://github.com/keplerproject/luarocks/wiki/Release-history">ChangeLog</a>: <code>make bootstrap</code> is now an advertised option for <strong>installing LuaRocks itself as a rock</strong> on Unix systems That means that if you go this way you can upgrade <code>luarocks</code> via <code>luarocks install</code>:</p></blockquote><blockquote><p>Those of you who installed LuaRocks 2.1.0 or later by using <code>make bootstrap</code> on Unix may upgrade by simply running: <code>luarocks install luarocks</code></p></blockquote><p>from <a href="http://sourceforge.net/p/luarocks/mailman/message/33607776/">[ANN] LuaRocks 2.2.1</a>.</p><p>因此, <code>make bootstrap</code> 是推荐方式, 这种方式安装后你甚至可以用<code>luarocks install luarocks</code> 来更新 luarocks自己。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> <span class="token function">make</span> bootstrap </span><span class="code-line"><span class="token function">mkdir</span> <span class="token parameter variable">-p</span> <span class="token string">&quot;build&quot;</span> </span><span class="code-line"><span class="token function">mkdir</span> <span class="token parameter variable">-p</span> .luarocks </span><span class="code-line"><span class="token function">cp</span> ./build/config-5.1.lua .luarocks/config-5.1.lua </span><span class="code-line"><span class="token function">rm</span> <span class="token parameter variable">-f</span> src/luarocks/core/hardcoded.lua </span><span class="code-line"><span class="token builtin class-name">echo</span> <span class="token string">&quot;#!/bin/sh&quot;</span> <span class="token operator">&gt;</span> luarocks </span><span class="code-line"><span class="token builtin class-name">echo</span> <span class="token string">&quot;unset LUA_PATH LUA_PATH_5_2 LUA_PATH_5_3 LUA_PATH_5_4 LUA_CPATH LUA_CPATH_5_2 LUA_CPATH_5_3 LUA_CPATH_5_4&quot;</span> <span class="token operator">&gt;&gt;</span> luarocks </span><span class="code-line"><span class="token builtin class-name">echo</span> <span class="token string">&#x27;LUAROCKS_SYSCONFDIR=&quot;/usr/local/etc/luarocks&quot; LUA_PATH=&quot;/home/ttys3/build/luarocks-3.5.0/src/?.lua;;&quot; exec &quot;/usr/bin/lua-5.1&quot; &quot;/home/ttys3/build/luarocks-3.5.0/src/bin/luarocks&quot; --project-tree=&quot;/home/ttys3/build/luarocks-3.5.0/lua_modules&quot; &quot;$@&quot;&#x27;</span> <span class="token operator">&gt;&gt;</span> luarocks </span><span class="code-line"><span class="token function">chmod</span> +rx ./luarocks </span><span class="code-line">./luarocks init </span><span class="code-line"> </span><span class="code-line">Initializing project <span class="token string">&#x27;luarocks-3.5.0&#x27;</span> <span class="token keyword">for</span> Lua <span class="token number">5.1</span> <span class="token punctuation">..</span>. </span><span class="code-line">----------------------------------------------------- </span><span class="code-line"> </span><span class="code-line">Checking your Lua installation <span class="token punctuation">..</span>. </span><span class="code-line">Adding entries to .gitignore <span class="token punctuation">..</span>. </span><span class="code-line">Preparing ./.luarocks/ <span class="token punctuation">..</span>. </span><span class="code-line">Wrote .luarocks/config-5.1.lua </span><span class="code-line">Preparing ./lua_modules/ <span class="token punctuation">..</span>. </span><span class="code-line">./luarocks already exists. Not overwriting it<span class="token operator">!</span> </span><span class="code-line">Preparing ./lua <span class="token keyword">for</span> version <span class="token number">5.1</span><span class="token punctuation">..</span>. </span><span class="code-line"><span class="token function">mkdir</span> <span class="token parameter variable">-p</span> <span class="token string">&quot;/usr/local/etc/luarocks&quot;</span> </span><span class="code-line"><span class="token function">install</span> <span class="token parameter variable">-m</span> <span class="token number">644</span> <span class="token string">&quot;build/config-5.1.lua&quot;</span> <span class="token string">&quot;/usr/local/etc/luarocks/config-5.1.lua&quot;</span> </span><span class="code-line">./luarocks <span class="token function">make</span> <span class="token parameter variable">--tree</span><span class="token operator">=</span><span class="token string">&quot;/usr/local&quot;</span> </span><span class="code-line"> </span><span class="code-line">No existing manifest. Attempting to rebuild<span class="token punctuation">..</span>. </span><span class="code-line">luarocks <span class="token number">3.5</span>.0-1 is now installed <span class="token keyword">in</span> /usr/local <span class="token punctuation">(</span>license: MIT<span class="token punctuation">)</span> </span></code></pre></div><p>可以看到, luarocks 被安装在 <code>/usr/local/share/lua/5.1/luarocks</code></p><p>用户级目录在:<code>~/.luarocks</code></p><p>系统配置在 <code>/usr/local/etc/luarocks</code> 头文件在 <code>/usr/include/lua-5.1</code></p><p>lua5.1 (dnf 安装的) 本身的lib在: <code>/lib64/lua/5.1</code></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ luarocks <span class="token parameter variable">--version</span> </span><span class="code-line">/usr/local/bin/luarocks <span class="token number">3.5</span>.0 </span><span class="code-line">LuaRocks main command-line interface </span></code></pre></div><blockquote><p>注: 其实像 ArchLinux 和 Fedora 本身带的 luarocks 包是比较新的,是可以不用自己编译的。</p></blockquote><h2 id="小试牛刀"><a href="#小试牛刀" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>小试牛刀</h2><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">luarocks <span class="token function">install</span> <span class="token parameter variable">--local</span> fzy </span><span class="code-line">Installing https://luarocks.org/fzy-0.4-1.rockspec </span><span class="code-line">Cloning into <span class="token string">&#x27;fzy-lua&#x27;</span><span class="token punctuation">..</span>. </span><span class="code-line">remote: Enumerating objects: <span class="token number">24</span>, done. </span><span class="code-line">remote: Counting objects: <span class="token number">100</span>% <span class="token punctuation">(</span><span class="token number">24</span>/24<span class="token punctuation">)</span>, done. </span><span class="code-line">remote: Compressing objects: <span class="token number">100</span>% <span class="token punctuation">(</span><span class="token number">20</span>/20<span class="token punctuation">)</span>, done. </span><span class="code-line">remote: Total <span class="token number">24</span> <span class="token punctuation">(</span>delta <span class="token number">0</span><span class="token punctuation">)</span>, reused <span class="token number">12</span> <span class="token punctuation">(</span>delta <span class="token number">0</span><span class="token punctuation">)</span>, pack-reused <span class="token number">0</span> </span><span class="code-line">Receiving objects: <span class="token number">100</span>% <span class="token punctuation">(</span><span class="token number">24</span>/24<span class="token punctuation">)</span>, <span class="token number">22.69</span> KiB <span class="token operator">|</span> <span class="token number">505.00</span> KiB/s, done. </span><span class="code-line">Note: switching to <span class="token string">&#x27;a3f1dd75725b535e6b00af84048c7e066432f530&#x27;</span><span class="token builtin class-name">.</span> </span><span class="code-line"> </span><span class="code-line">You are <span class="token keyword">in</span> <span class="token string">&#x27;detached HEAD&#x27;</span> state. You can <span class="token function">look</span> around, <span class="token function">make</span> experimental </span><span class="code-line">changes and commit them, and you can discard any commits you <span class="token function">make</span> <span class="token keyword">in</span> this </span><span class="code-line">state without impacting any branches by switching back to a branch. </span><span class="code-line"> </span><span class="code-line">If you want to create a new branch to retain commits you create, you may </span><span class="code-line"><span class="token keyword">do</span> so <span class="token punctuation">(</span>now or later<span class="token punctuation">)</span> by using <span class="token parameter variable">-c</span> with the switch command. Example: </span><span class="code-line"> </span><span class="code-line"> <span class="token function">git</span> switch <span class="token parameter variable">-c</span> <span class="token operator">&lt;</span>new-branch-name<span class="token operator">&gt;</span> </span><span class="code-line"> </span><span class="code-line">Or undo this operation with: </span><span class="code-line"> </span><span class="code-line"> <span class="token function">git</span> switch - </span><span class="code-line"> </span><span class="code-line">Turn off this advice by setting config variable advice.detachedHead to <span class="token boolean">false</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">fzy <span class="token number">0.4</span>-1 depends on lua <span class="token operator">&gt;=</span> <span class="token number">5.1</span> <span class="token punctuation">(</span><span class="token number">5.1</span>-1 provided by VM<span class="token punctuation">)</span> </span><span class="code-line">gcc <span class="token parameter variable">-O2</span> <span class="token parameter variable">-fPIC</span> -I/usr/include/lua-5.1 <span class="token parameter variable">-c</span> src/fzy_native.c <span class="token parameter variable">-o</span> src/fzy_native.o <span class="token parameter variable">-DLUA_COMPAT_5_1</span> </span><span class="code-line">gcc <span class="token parameter variable">-O2</span> <span class="token parameter variable">-fPIC</span> -I/usr/include/lua-5.1 <span class="token parameter variable">-c</span> src/match.c <span class="token parameter variable">-o</span> src/match.o <span class="token parameter variable">-DLUA_COMPAT_5_1</span> </span><span class="code-line">gcc <span class="token parameter variable">-shared</span> <span class="token parameter variable">-o</span> fzy_native.so src/fzy_native.o src/match.o </span><span class="code-line">No existing manifest. Attempting to rebuild<span class="token punctuation">..</span>. </span><span class="code-line">fzy <span class="token number">0.4</span>-1 is now installed <span class="token keyword">in</span> /home/ttys3/.luarocks <span class="token punctuation">(</span>license: MIT<span class="token punctuation">)</span> </span></code></pre></div><p>OK, 安装成功,我们看下都写入了啥文件:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ tree ~/.luarocks </span><span class="code-line">/home/ttys3/.luarocks </span><span class="code-line">├── config-5.1.lua </span><span class="code-line">├── lib </span><span class="code-line">│   └── luarocks </span><span class="code-line">│   └── rocks-5.1 </span><span class="code-line">│   ├── fzy </span><span class="code-line">│   │   └── <span class="token number">0.4</span>-1 </span><span class="code-line">│   │   ├── fzy-0.4-1.rockspec </span><span class="code-line">│   │   ├── rock_manifest </span><span class="code-line">│   │   └── <span class="token builtin class-name">test</span> </span><span class="code-line">│   │   ├── benchmark.lua </span><span class="code-line">│   │   ├── files.txt </span><span class="code-line">│   │   └── test.lua </span><span class="code-line">│   └── manifest </span><span class="code-line">├── lib64 </span><span class="code-line">│   └── lua </span><span class="code-line">│   └── <span class="token number">5.1</span> </span><span class="code-line">│   └── fzy_native.so </span><span class="code-line">└── share </span><span class="code-line"> └── lua </span><span class="code-line"> └── <span class="token number">5.1</span> </span><span class="code-line"> ├── fzy.lua </span><span class="code-line"> └── fzy_lua.lua </span><span class="code-line"> </span><span class="code-line"><span class="token number">12</span> directories, <span class="token number">10</span> files </span></code></pre></div><p><code>~/.luarocks/lib/luarocks/rocks-5.1</code> 相当于一个包管理数据库,里面记录了安装的rocks的元数据。</p><p><code>~/.luarocks/lib64/lua/5.1/</code> 下面是 so 文件</p><p><code>~/.luarocks/share/lua/5.1/</code> 下面是 *.lua文件</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ luarocks config <span class="token parameter variable">--scope</span> user config_files </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> nearest <span class="token operator">=</span> <span class="token string">&quot;/home/ttys3/.luarocks/config-5.1.lua&quot;</span>, </span><span class="code-line"> system <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">file</span> <span class="token operator">=</span> <span class="token string">&quot;/etc/luarocks/config-5.4.lua&quot;</span>, </span><span class="code-line"> found <span class="token operator">=</span> <span class="token boolean">true</span> </span><span class="code-line"> <span class="token punctuation">}</span>, </span><span class="code-line"> user <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">file</span> <span class="token operator">=</span> <span class="token string">&quot;/home/ttys3/.luarocks/config-5.1.lua&quot;</span>, </span><span class="code-line"> found <span class="token operator">=</span> <span class="token boolean">true</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>配置文件可以用 <code>LUAROCKS_CONFIG</code> 指定</p><p>用户配置一般是 <code>/home/ttys3/.luarocks/config-5.1.lua</code></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ bat /usr/local/etc/luarocks/config-5.1.lua </span><span class="code-line">-- LuaRocks configuration </span><span class="code-line"> </span><span class="code-line">rocks_trees <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token punctuation">{</span> name <span class="token operator">=</span> <span class="token string">&quot;user&quot;</span>, root <span class="token operator">=</span> home <span class="token punctuation">..</span> <span class="token string">&quot;/.luarocks&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">{</span> name <span class="token operator">=</span> <span class="token string">&quot;system&quot;</span>, root <span class="token operator">=</span> <span class="token string">&quot;/usr/local&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line">lua_interpreter <span class="token operator">=</span> <span class="token string">&quot;lua-5.1&quot;</span><span class="token punctuation">;</span> </span><span class="code-line">variables <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> LUA_DIR <span class="token operator">=</span> <span class="token string">&quot;/usr&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> LUA_INCDIR <span class="token operator">=</span> <span class="token string">&quot;/usr/include/lua-5.1&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> LUA_BINDIR <span class="token operator">=</span> <span class="token string">&quot;/usr/bin&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>注意这里的rocks_trees, 分为user和system级别的,并不是一个直接的路径,实际上通过默认安装生成的文件可以发现, 它是 <code>rocks_trees.root .. &quot;/share/lua/5.1/&quot; .. &quot;*.lua文件或目录&quot;</code> 如:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ tree <span class="token parameter variable">-L</span> <span class="token number">1</span> /usr/local/share/lua/5.1/ </span><span class="code-line">/usr/local/share/lua/5.1/ </span><span class="code-line">└── luarocks </span><span class="code-line"> </span><span class="code-line"><span class="token number">1</span> directory, <span class="token number">0</span> files </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">❯ tree /home/ttys3/.luarocks/share/lua/5.1/ </span><span class="code-line">/home/ttys3/.luarocks/share/lua/5.1/ </span><span class="code-line">├── fzy.lua </span><span class="code-line">└── fzy_lua.lua </span><span class="code-line"> </span><span class="code-line"><span class="token number">0</span> directories, <span class="token number">2</span> files </span><span class="code-line"> </span></code></pre></div><p>默认配置<code>lib_modules_path</code>是错的, 这个值默认在Fedora和Ubuntu下面都是<code>/lib/lua/5.1</code>, 然而这个路径在这两个系统上都是不存在的。 Fedora下通过dnf安装的lua 5.1 是<code>/lib64/lua/5.1</code>, 而Ubuntu 20.10 通过apt 安装的,则是在 <code>/usr/share/lua/5.1</code></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ luarocks config <span class="token parameter variable">--scope</span> user lib_modules_path </span><span class="code-line">/lib/lua/5.1 </span><span class="code-line">❯ <span class="token function">ls</span> /lib/lua/5.1 </span><span class="code-line">ls: cannot access <span class="token string">&#x27;/lib/lua/5.1&#x27;</span><span class="token builtin class-name">:</span> No such <span class="token function">file</span> or directory </span><span class="code-line"><span class="token comment"># Fedora</span> </span><span class="code-line">❯ <span class="token function">ls</span> /lib64/lua/5.1 </span><span class="code-line">bit.so compat53/ _cqueues.so lfs.so lpeg.so lpeg.so.1.0.2 luv.so mime/ mpack.so _openssl.so psl.so socket/ ssl.so </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Ubuntu</span> </span><span class="code-line">❯ <span class="token function">ls</span> /usr/share/lua/5.1 </span><span class="code-line">basexx.lua compat53/ cqueues.lua http/ json.lua ltn12.lua mime.lua openssl.lua socket/ ssl/ </span><span class="code-line">cjson/ cqueues/ fifo.lua json/ lpeg_patterns/ lxp/ openssl/ re.lua socket.lua ssl.lua </span></code></pre></div><p>Fedora 33 下修正:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ luarocks config <span class="token parameter variable">--scope</span> user lib_modules_path /lib64/lua/5.1 </span><span class="code-line">Wrote </span><span class="code-line"> lib_modules_path <span class="token operator">=</span> <span class="token string">&quot;/lib64/lua/5.1&quot;</span> </span><span class="code-line">to </span><span class="code-line"> /home/ttys3/.luarocks/config-5.1.lua </span></code></pre></div><p>Ubuntu 20.10 下修正:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ luarocks config <span class="token parameter variable">--scope</span> user lib_modules_path /usr/share/lua/5.1 </span><span class="code-line">Wrote </span><span class="code-line"> lib_modules_path <span class="token operator">=</span> <span class="token string">&quot;/usr/share/lua/5.1&quot;</span> </span><span class="code-line">to </span><span class="code-line"> /home/ttys3/.luarocks/config-5.1.lua </span></code></pre></div><p>如果没有,这里luarocks会自动生成配置文件.</p><h3 id="rocks-默认安装到用户目录下"><a href="#rocks-默认安装到用户目录下" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>rocks 默认安装到用户目录下</h3><p><a href="https://github.com/luarocks/luarocks/issues/356">https://github.com/luarocks/luarocks/issues/356</a></p><p>You mean --local?</p><p>You can also put <code>local_by_default=true</code> in the ~/.luarocks/config.lua file and this flag will be assumed by default. It&#x27;s great for running LuaRocks as non-root.</p><p>最终的文件:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ bat /home/ttys3/.luarocks/config-5.1.lua </span><span class="code-line">lib_modules_path <span class="token operator">=</span> <span class="token string">&quot;/lib64/lua/5.1&quot;</span> </span><span class="code-line">local_by_default <span class="token operator">=</span> <span class="token boolean">true</span> </span></code></pre></div><h2 id="troubleshoot"><a href="#troubleshoot" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Troubleshoot</h2><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">❯ luarocks config </span><span class="code-line">/usr/bin/lua5.4: /usr/share/lua/5.4/luarocks/fs.lua:95: <span class="token builtin class-name">local</span> <span class="token string">&#x27;each_platform&#x27;</span> is not callable <span class="token punctuation">(</span>a nil value<span class="token punctuation">)</span> </span><span class="code-line">stack traceback: </span><span class="code-line"> /usr/share/lua/5.4/luarocks/fs.lua:95: <span class="token keyword">in</span> upvalue <span class="token string">&#x27;load_platform_fns&#x27;</span> </span><span class="code-line"> /usr/share/lua/5.4/luarocks/fs.lua:122: <span class="token keyword">in</span> <span class="token keyword">function</span> <span class="token string">&#x27;luarocks.fs.init&#x27;</span> </span><span class="code-line"> /usr/share/lua/5.4/luarocks/cmd.lua:500: <span class="token keyword">in</span> <span class="token keyword">function</span> <span class="token string">&#x27;luarocks.cmd.run_command&#x27;</span> </span><span class="code-line"> /usr/bin/luarocks:38: <span class="token keyword">in</span> main chunk </span><span class="code-line"> <span class="token punctuation">[</span>C<span class="token punctuation">]</span>: <span class="token keyword">in</span> ? </span><span class="code-line"> </span></code></pre></div><p>错误看着很奇怪,同时安装了lua5.1 和 lua5.4, 但是 lua5.1 应该路径优先在前面的,为什么会报 lua5.4 的错误? 后面发现是将配置改错了:</p><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line">variables <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> LUA <span class="token operator">=</span> <span class="token string">&quot;/usr/bin/lua5.1&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> LUA_DIR <span class="token operator">=</span> <span class="token string">&quot;/usr&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> LUA_BINDIR <span class="token operator">=</span> <span class="token string">&quot;/usr/bin&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>里面的 <code>;</code> 被我删除了,因为写 Golang 的习惯是,末尾的 <code>;</code> 是编译器自动加的,习惯性地就删除了。 但是在这个 table 里,实际上是 lua 里的 <code>;</code> 相当于 Golang 里面的 <code>,</code>, 修正配置,就 OK 了</p><h2 id="my-config"><a href="#my-config" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>My config</h2><p><a href="config-5.1.lua">config-5.1.lua</a></p><div class="relative"><pre><code class="code-highlight language-lua"><span class="code-line"><span class="token comment">-- ~/.luarocks/config-5.1.lua</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">-- default config see https://github.com/luarocks/luarocks/blob/d4e82aae9f411d5d2cac10f7e043a0c3c6180eb1/src/luarocks/core/cfg.lua#L167</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">-- http://lua-users.org/wiki/LuaRocksConfig</span> </span><span class="code-line"><span class="token comment">-- https://github.com/luarocks/luarocks/wiki/Dependencies</span> </span><span class="code-line"><span class="token comment">-- https://github.com/luarocks/luarocks/wiki/Documentation</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">lua_version <span class="token operator">=</span> <span class="token string">&quot;5.1&quot;</span> </span><span class="code-line"> </span><span class="code-line">local_by_default <span class="token operator">=</span> <span class="token keyword">true</span> </span><span class="code-line"> </span><span class="code-line">lua_interpreter <span class="token operator">=</span> <span class="token string">&quot;lua&quot;</span> <span class="token operator">..</span> lua_version </span><span class="code-line"> </span><span class="code-line"><span class="token comment">-- do not prepend `/usr` to lua_modules_path or lib_modules_path</span> </span><span class="code-line"><span class="token comment">-- no need to change the default generally.</span> </span><span class="code-line"><span class="token comment">-- otherwise both `deploy_lib_dir` and `deploy_lua_dir` value will be wrong</span> </span><span class="code-line"><span class="token comment">----------------------------------------------------------------</span> </span><span class="code-line"><span class="token comment">-- remember: </span> </span><span class="code-line"><span class="token comment">-- `home_tree = &quot;/home/ttys3/.luarocks&quot;`</span> </span><span class="code-line"><span class="token comment">-- `deploy_lua_dir = home_tree .. lua_modules_path`</span> </span><span class="code-line"><span class="token comment">-- `deploy_lib_dir = home_tree .. lib_modules_path`</span> </span><span class="code-line"><span class="token comment">----------------------------------------------------------------</span> </span><span class="code-line"><span class="token comment">-- lua_modules_path = &quot;/share/lua/&quot;..lua_version</span> </span><span class="code-line"><span class="token comment">-- lib_modules_path = &quot;/lib/lua/&quot;..lua_version</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">-- we need correct `lib_modules_path` here</span> </span><span class="code-line">lib_modules_path <span class="token operator">=</span> <span class="token string">&quot;/lib64/lua/&quot;</span><span class="token operator">..</span>lua_version </span><span class="code-line"> </span><span class="code-line"><span class="token comment">-- for 5.1 ROCKS_TREE is `/home/ttys3/.luarocks/lib/luarocks/rocks-5.1`</span> </span><span class="code-line"><span class="token comment">-- so rocks_subdir is `lib/luarocks/rocks-5.1`, no need to change the default</span> </span><span class="code-line"><span class="token comment">-- set it to full absolute path is incorrect, it does not need the `~/.luarocks` part</span> </span><span class="code-line"><span class="token comment">-- otherwise both `variables.ROCKS_TREE` and `rocks_dir` value will be wrong</span> </span><span class="code-line"><span class="token comment">-- remember: `rocks_dir = home_tree .. rocks_subdir`</span> </span><span class="code-line"><span class="token comment">-- system: /usr/lib/luarocks/rocks-5.1</span> </span><span class="code-line"><span class="token comment">-- user: /home/ttys3/.luarocks/lib/luarocks/rocks-5.1</span> </span><span class="code-line"><span class="token comment">-- rocks_subdir = &quot;/lib/luarocks/rocks-&quot;..lua_version</span> </span><span class="code-line"> </span><span class="code-line">connection_timeout <span class="token operator">=</span> <span class="token number">30</span> <span class="token comment">-- 0 = no timeout</span> </span><span class="code-line"> </span><span class="code-line">variables <span class="token operator">=</span> <span class="token punctuation">{</span> </span><span class="code-line"> LUA <span class="token operator">=</span> <span class="token string">&quot;/usr/bin/lua&quot;</span> <span class="token operator">..</span> lua_version<span class="token punctuation">,</span> </span><span class="code-line"> LUA_DIR <span class="token operator">=</span> <span class="token string">&quot;/usr&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> LUA_BINDIR <span class="token operator">=</span> <span class="token string">&quot;/usr/bin&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://github.com/luarocks/luarocks/wiki/Installation-instructions-for-Unix">https://github.com/luarocks/luarocks/wiki/Installation-instructions-for-Unix</a></p><p><a href="http://lua-users.org/wiki/LuaRocksConfig">http://lua-users.org/wiki/LuaRocksConfig</a></p><p><a href="https://github.com/luarocks/luarocks/wiki/config-file-format">https://github.com/luarocks/luarocks/wiki/config-file-format</a></p><p><a href="https://stackoverflow.com/a/29340739/13267147">https://stackoverflow.com/a/29340739/13267147</a></p> Tue, 05 Jan 2021 18:15:44 GMT ttyS3 lualuarockslinuxfedoraubuntu https://ttys3.dev/blog/how-to-boot-ubuntu-live-cd-iso-from-grub2 如何从 grub2 启动 Ubuntu Live CD iso https://ttys3.dev/blog/how-to-boot-ubuntu-live-cd-iso-from-grub2 <p>上次写了<a href="/post/linux/fedora/how-to-boot-fedora32-live-cd-iso-from-grub2">《如何从 grub2 启动 Fedora32 Live CD iso》</a> , 这次顺便把 <code>Ubuntu</code> 的也补一下吧。</p><p>公司开发环境为了大家统一,全部采用的 Ubuntu.</p><p>这年头也很少随身带U盘了,因此,只靠硬盘, 自己能求自己,还是能在关键时候有用的。</p><h2 id="下载live-cd-iso并校验"><a href="#下载live-cd-iso并校验" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>下载live cd iso并校验</h2><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LZO</span> https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/groovy/ubuntu-20.10-desktop-amd64.iso </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/groovy/SHA256SUMS </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/groovy/SHA256SUMS.gpg </span></code></pre></div><p>校验 可 参考官方文档 <a href="https://ubuntu.com/tutorials/how-to-verify-ubuntu#4-retrieve-the-correct-signature-key">https://ubuntu.com/tutorials/how-to-verify-ubuntu#4-retrieve-the-correct-signature-key</a></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">gpg --keyid-format long <span class="token variable parameter">--verify</span> SHA256SUMS.gpg SHA256SUMS </span><span class="code-line">sha256sum <span class="token variable parameter">-c</span> SHA256SUMS </span></code></pre></div><h2 id="增加grub2启动项"><a href="#增加grub2启动项" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>增加grub2启动项</h2><p>先准备下文件,由于Ubuntu默认划分的 <code>/boot</code> 分区较小,因此不能放下live cd iso.</p><p>直接放到 <code>/</code> 吧。 准备下目录: <code>sudo mkdir /opt/iso</code>, 然后把 iso 文件 copy 到这个目录。</p><p>注意,这里的<code>/</code> 分区我使用的是LVM, 因此,我们要使用 <code>sudo blkid</code> 找出 <code>/</code> 所在的 LV 的 UUID.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> blkid </span><span class="code-line">/dev/mapper/vgubuntu-swap_1: <span class="token variable assign-left">UUID</span><span class="token operator">=</span><span class="token string">&quot;f63131c3-9d02-4813-9db9-d85571f09084&quot;</span> <span class="token variable assign-left">TYPE</span><span class="token operator">=</span><span class="token string">&quot;swap&quot;</span> </span><span class="code-line">/dev/mapper/vgubuntu-root: <span class="token variable assign-left">UUID</span><span class="token operator">=</span><span class="token string">&quot;cb94816d-569d-4658-963c-eb675052fc98&quot;</span> <span class="token variable assign-left">BLOCK_SIZE</span><span class="token operator">=</span><span class="token string">&quot;4096&quot;</span> <span class="token variable assign-left">TYPE</span><span class="token operator">=</span><span class="token string">&quot;ext4&quot;</span> </span><span class="code-line">/dev/sda1: <span class="token variable assign-left">UUID</span><span class="token operator">=</span><span class="token string">&quot;ba87f398-f52b-420f-9d19-af30a320c8f5&quot;</span> <span class="token variable assign-left">BLOCK_SIZE</span><span class="token operator">=</span><span class="token string">&quot;4096&quot;</span> <span class="token variable assign-left">TYPE</span><span class="token operator">=</span><span class="token string">&quot;xfs&quot;</span> <span class="token variable assign-left">PARTLABEL</span><span class="token operator">=</span><span class="token string">&quot;Linux filesystem&quot;</span> <span class="token variable assign-left">PARTUUID</span><span class="token operator">=</span><span class="token string">&quot;e21fd454-dc9a-41cb-8c72-c9fb05cb5d41&quot;</span> </span><span class="code-line">/dev/nvme0n1p1: <span class="token variable assign-left">UUID</span><span class="token operator">=</span><span class="token string">&quot;97CB-9857&quot;</span> <span class="token variable assign-left">BLOCK_SIZE</span><span class="token operator">=</span><span class="token string">&quot;512&quot;</span> <span class="token variable assign-left">TYPE</span><span class="token operator">=</span><span class="token string">&quot;vfat&quot;</span> <span class="token variable assign-left">PARTUUID</span><span class="token operator">=</span><span class="token string">&quot;ca61970c-01&quot;</span> </span><span class="code-line">/dev/nvme0n1p5: <span class="token variable assign-left">UUID</span><span class="token operator">=</span><span class="token string">&quot;C7sb3l-laqt-gLDw-ji2s-yC3r-x5bw-Axa9yu&quot;</span> <span class="token variable assign-left">TYPE</span><span class="token operator">=</span><span class="token string">&quot;LVM2_member&quot;</span> <span class="token variable assign-left">PARTUUID</span><span class="token operator">=</span><span class="token string">&quot;ca61970c-05&quot;</span> </span></code></pre></div><p>注意这里 <code>/dev/mapper/vgubuntu-root: UUID=&quot;cb94816d-569d-4658-963c-eb675052fc98&quot; BLOCK_SIZE=&quot;4096&quot; TYPE=&quot;ext4&quot;</code> 就是 <code>/</code> 所在的LV了。 在grub2里,我们只需要取这里的<code>cb94816d-569d-4658-963c-eb675052fc98</code> 即可。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token important shebang">#!/bin/sh</span> </span><span class="code-line"><span class="token builtin class-name">exec</span> <span class="token function">tail</span> <span class="token variable parameter">-n</span> +3 <span class="token variable">$0</span> </span><span class="code-line"><span class="token comment"># This file provides an easy way to add custom menu entries. Simply type the</span> </span><span class="code-line"><span class="token comment"># menu entries you want to add after this comment. Be careful not to change</span> </span><span class="code-line"><span class="token comment"># the &#x27;exec tail&#x27; line above.</span> </span><span class="code-line"> </span><span class="code-line">menuentry <span class="token string">&quot;Ubuntu 20.10 ISO&quot;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token builtin class-name">set</span> <span class="token variable assign-left">isofile</span><span class="token operator">=</span><span class="token string">&quot;/opt/iso/ubuntu-20.10-desktop-amd64.iso&quot;</span> </span><span class="code-line"> <span class="token comment"># or set isofile=&quot;/&lt;username&gt;/Downloads/ubuntu-20.04-desktop-amd64.iso&quot;</span> </span><span class="code-line"> <span class="token comment"># if you use a single partition for your $HOME</span> </span><span class="code-line"> rmmod tpm </span><span class="code-line"> search --no-floppy --fs-uuid <span class="token variable parameter">--set</span><span class="token operator">=</span>root cb94816d-569d-4658-963c-eb675052fc98 </span><span class="code-line"> loopback loop <span class="token punctuation">(</span><span class="token variable">$root</span><span class="token punctuation">)</span><span class="token variable">$isofile</span> </span><span class="code-line"> linux <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/casper/vmlinuz <span class="token variable assign-left">boot</span><span class="token operator">=</span>casper iso-scan/filename<span class="token operator">=</span><span class="token variable">$isofile</span> noprompt noeject </span><span class="code-line"> initrd <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/casper/initrd </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h2 id="grub2-配置调整"><a href="#grub2-配置调整" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>grub2 配置调整</h2><p>Fedora 和 Ubuntu 现在都默认不显示grub menu了 (要开机时按esc才显示), 可以通过修改配置调整成总是显示:</p><p>修改 <code>/etc/default/grub</code> :</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment">#GRUB_TIMEOUT_STYLE=hidden</span> </span><span class="code-line"><span class="token comment">#GRUB_TIMEOUT_STYLE=countdown</span> </span><span class="code-line"><span class="token attr-name key">GRUB_TIMEOUT_STYLE</span><span class="token punctuation">=</span><span class="token attr-value value">menu</span> </span></code></pre></div><p>文档解释: <code>GRUB_TIMEOUT_STYLE</code></p><blockquote><p>If this option is unset or set to ‘menu’, then GRUB will display the menu and then wait for the timeout set by ‘GRUB_TIMEOUT’ to expire before booting the default entry. Pressing a key interrupts the timeout.</p><p>If this option is set to ‘countdown’ or ‘hidden’, then, before displaying the menu, GRUB will wait for the timeout set by ‘GRUB_TIMEOUT’ to expire. If ESC is pressed during that time, it will display the menu and wait for input. If a hotkey associated with a menu entry is pressed, it will boot the associated menu entry immediately. If the timeout expires before either of these happens, it will boot the default entry. In the ‘countdown’ case, it will show a one-line indication of the remaining time.</p></blockquote><h2 id="更新-grub2-配置文件"><a href="#更新-grub2-配置文件" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>更新 grub2 配置文件</h2><p>Ubuntu 下面有一个比较方便的 <code>update-grub2</code> 用来更新grub2配置, 该命令实际上是对 <code>grub2-mkconfig</code> 的便捷封装, 你不用指定配置文件路径,直接跑就行了。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> update-grub2 </span><span class="code-line">Sourcing <span class="token function">file</span> <span class="token variable"><span class="token variable">`</span>/etc/default/grub&#x27; </span></span><span class="code-line"><span class="token variable">Sourcing <span class="token function">file</span> <span class="token variable">`</span></span>/etc/default/grub.d/init-select.cfg&#x27; </span><span class="code-line">Generating grub configuration <span class="token function">file</span> <span class="token punctuation">..</span>. </span><span class="code-line">Found linux image: /boot/vmlinuz-5.8.0-29-generic </span><span class="code-line">Found initrd image: /boot/initrd.img-5.8.0-29-generic </span><span class="code-line">Found linux image: /boot/vmlinuz-5.8.0-28-generic </span><span class="code-line">Found initrd image: /boot/initrd.img-5.8.0-28-generic </span><span class="code-line">Found linux image: /boot/vmlinuz-5.8.0-26-generic </span><span class="code-line">Found initrd image: /boot/initrd.img-5.8.0-26-generic </span><span class="code-line">Found memtest86+ image: /boot/memtest86+.elf </span><span class="code-line">Found memtest86+ image: /boot/memtest86+.bin </span><span class="code-line"><span class="token keyword">done</span> </span></code></pre></div><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://www.gnu.org/software/grub/manual/grub/html_node/Simple-configuration.html">https://www.gnu.org/software/grub/manual/grub/html_node/Simple-configuration.html</a></p><p><a href="https://unix.stackexchange.com/questions/516429/boot-iso-file-located-on-lvm-from-grub2">https://unix.stackexchange.com/questions/516429/boot-iso-file-located-on-lvm-from-grub2</a></p><p><a href="https://superuser.com/a/1289853/1162309">https://superuser.com/a/1289853/1162309</a></p><p><a href="https://help.ubuntu.com/community/Grub2/ISOBoot#ISO_File_Location">https://help.ubuntu.com/community/Grub2/ISOBoot#ISO_File_Location</a></p> Sat, 26 Dec 2020 15:07:46 GMT ttyS3 ubuntulive-cdisolinux https://ttys3.dev/blog/charles-root-ca-installation-on-fedora33-centos8 如何在Fedora33/CentOS8上安装Charles根证书 https://ttys3.dev/blog/charles-root-ca-installation-on-fedora33-centos8 <p>开发机上跑着Charles, 同时本机又有程序想通过Charles来抓包, 需要tls证书被信任才行(依赖的库强制校验证书). 所以才有这个需求。</p><p>此方法通用,适用于安装任何root ca.</p><h2 id="root-ca-installation"><a href="#root-ca-installation" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>root ca installation</h2><p>较新版本的 Charles 现在默认会同时生成 <code>charles-proxy-ssl-proxying-certificate.cer</code>, <code>charles-proxy-ssl-proxying-certificate.pem</code> 和 <code>keystore</code> 3个文件</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">cd</span> ~/.charles/ca </span><span class="code-line"><span class="token function">sudo</span> trust anchor <span class="token parameter variable">--store</span> ./charles-proxy-ssl-proxying-certificate.pem </span><span class="code-line"><span class="token comment"># 证书会写到 /etc/pki/ca-trust/source 这个目录下</span> </span></code></pre></div><h2 id="manual-installation-method"><a href="#manual-installation-method" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>manual installation method</h2><p>If you get &quot;no configured writable location&quot; or a similar error, import the CA manually:</p><p>Copy the certificate to the <code>/etc/pki/ca-trust/source/anchors</code> directory. Run <code>update-ca-trust</code> as root.</p><p>对于 ArchLinux, 它是安装到 <code>/etc/ca-certificates/trust-source/</code> 目录。 手动安装路径为 <code>/etc/ca-certificates/trust-source/anchors</code></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">cd</span> ~/.charles/ca </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 如果没有 pem 文件, 先将der格式的证书转换成pem格式</span> </span><span class="code-line"><span class="token comment"># openssl x509 -inform DER -in charles-proxy-ssl-proxying-certificate.cer -out charles-proxy-ssl-proxying-certificate.pem</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 复制转换好的ca到/etc/pki/ca-trust/source/anchors/</span> </span><span class="code-line"><span class="token function">cp</span> charles-proxy-ssl-proxying-certificate.pem /etc/pki/ca-trust/source/anchors/charles-ca.pem </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 执行</span> </span><span class="code-line">update-ca-trust extract </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># verify</span> </span><span class="code-line">❯ openssl verify /etc/pki/ca-trust/source/anchors/charles-ca.pem </span><span class="code-line">/etc/pki/ca-trust/source/anchors/charles-ca.crt: OK </span></code></pre></div><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://access.redhat.com/solutions/1519813">https://access.redhat.com/solutions/1519813</a></p><p>ubuntu: <a href="https://askubuntu.com/questions/73287/how-do-i-install-a-root-certificate">https://askubuntu.com/questions/73287/how-do-i-install-a-root-certificate</a></p><p>Adding a trusted CA certificate <a href="https://wiki.archlinux.org/title/User:Grawity/Adding_a_trusted_CA_certificate">https://wiki.archlinux.org/title/User:Grawity/Adding_a_trusted_CA_certificate</a></p> Sun, 20 Dec 2020 14:19:56 GMT ttyS3 FedoraCharlesCentOS8 https://ttys3.dev/blog/run-baidunetdisk-on-fedora-is-hard Fedora 33 中使用百度网盘Linux版的艰难历程 https://ttys3.dev/blog/run-baidunetdisk-on-fedora-is-hard <h2 id="问题"><a aria-hidden="true" href="#问题" tabindex="-1"><span class="icon icon-link"></span></a>问题</h2><p>百度网盘推出Linux客户端已经有一段时间了。 期间,在Fedora32时我就已经给他们提过一个启动即crash的问题,后面一直也没修复.</p><div><img alt="baidu-netdisk-crash-2020-11-12_19-15.png" src="https://ttys3.dev/static/assets/baidu-netdisk-crash-2020-11-12_19-15-UWTX5M5D.png" width="3840" height="1781"/></div><p>这都 Fedora 33了,我又提了一次,而且还把gdb的backtrace发给了他们,显示已经处理。 实际上几个月过去了都没见动静。只能自己动手,丰衣足食了。</p><h2 id="解决"><a aria-hidden="true" href="#解决" tabindex="-1"><span class="icon icon-link"></span></a>解决</h2><p>老灯注意到, 百度网盘链接的库都是比较老的,因此那个客户端在Ubuntu 18.04 上面肯定是可以正常运行。</p><p>那个 rpm 包压根不是对标最新的Fedora的,而是给那些基于RHEL的同样使用rpm包管理的古董国产操作系统使用的。</p><p>因此老灯下载 baidunetdisk_3.5.0_amd64.deb,并解压出实际的程序.</p><p>首先我们跑一下,看看bt 吧:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">Thread <span class="token number">1</span> <span class="token string">&quot;baidunetdisk&quot;</span> received signal SIGSEGV, Segmentation fault. </span><span class="code-line">0x00007ffff5096179 <span class="token keyword">in</span> EVP_MD_CTX_clear_flags <span class="token punctuation">(</span><span class="token punctuation">)</span> from /lib64/libcrypto.so.1.1 </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">(</span>gdb<span class="token punctuation">)</span> bt </span><span class="code-line"><span class="token comment">#0 0x00007ffff5096179 in EVP_MD_CTX_clear_flags () at /lib64/libcrypto.so.1.1</span> </span><span class="code-line"><span class="token comment">#1 0x00007ffff508b261 in EVP_DigestInit_ex () at /lib64/libcrypto.so.1.1</span> </span><span class="code-line"><span class="token comment">#2 0x00007ffff50ab1e8 in HMAC_Init_ex () at /lib64/libcrypto.so.1.1</span> </span><span class="code-line"><span class="token comment">#3 0x00007fffd1a92766 in sqlcipher_openssl_hmac</span> </span><span class="code-line"> <span class="token punctuation">(</span>ctx<span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, <span class="token variable assign-left">hmac_key</span><span class="token operator">=</span>0x227a99ce02d8 <span class="token string">&quot;<span class="token entity" title="\f">\f</span>&gt;@)YUj<span class="token entity" title="\001">\001</span><span class="token entity" title="\346">\346</span><span class="token entity" title="\063">\063</span>vr<span class="token entity" title="\312">\312</span><span class="token entity" title="\062">\062</span><span class="token entity" title="\016">\016</span><span class="token entity" title="\243">\243</span><span class="token entity" title="\232">\232</span><span class="token entity" title="\312">\312</span><span class="token entity" title="\334">\334</span><span class="token entity" title="\324">\324</span><span class="token entity" title="\302">\302</span><span class="token entity" title="\027">\027</span><span class="token entity" title="\201">\201</span>-<span class="token entity" title="\330">\330</span>ƨ<span class="token entity" title="\213">\213</span>É&lt;)&quot;</span>, <span class="token variable assign-left">key_sz</span><span class="token operator">=</span><span class="token number">32</span>, <span class="token variable assign-left">in</span><span class="token operator">=</span>0x227a9a00b548 <span class="token string">&quot;<span class="token entity" title="\250">\250</span><span class="token entity" title="\235">\235</span>J_h1E<span class="token entity" title="\214">\214</span><span class="token entity" title="\v">\v</span><span class="token entity" title="\033">\033</span>u<span class="token entity" title="\266">\266</span><span class="token entity" title="\342">\342</span>P.<span class="token entity" title="\240">\240</span><span class="token entity" title="\063">\063</span><span class="token entity" title="\244">\244</span><span class="token entity" title="\337">\337</span>V<span class="token entity" title="\313">\313</span><span class="token entity" title="\360">\360</span>T<span class="token entity" title="\r">\r</span>qu&lt;c:<span class="token entity" title="\303">\303</span>E<span class="token entity" title="\234">\234</span><span class="token entity" title="\061">\061</span>-<span class="token entity" title="\216">\216</span><span class="token entity" title="\365">\365</span><span class="token entity" title="\255">\255</span><span class="token entity" title="\033">\033</span>Dz<span class="token entity" title="\203">\203</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\027">\027</span><span class="token entity" title="\257">\257</span><span class="token entity" title="\215">\215</span><span class="token entity" title="\033">\033</span><span class="token entity" title="\070">\070</span>{i9H<span class="token entity" title="\376">\376</span><span class="token entity" title="\346">\346</span>H<span class="token entity" title="\223">\223</span>DB<span class="token entity" title="\244">\244</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\314">\314</span>d<span class="token entity" title="\302">\302</span><span class="token entity" title="\022">\022</span><span class="token entity" title="\310">\310</span><span class="token entity" title="\376">\376</span><span class="token entity" title="\315">\315</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\343">\343</span><span class="token entity" title="\&quot;">\&quot;</span><span class="token entity" title="\362">\362</span>e<span class="token entity" title="\227">\227</span><span class="token entity" title="\252">\252</span>T<span class="token entity" title="\363">\363</span><span class="token entity" title="\215">\215</span><span class="token entity" title="\351">\351</span><span class="token entity" title="\323">\323</span><span class="token entity" title="\005">\005</span><span class="token entity" title="\271">\271</span><span class="token entity" title="\022">\022</span>ǎ<span class="token entity" title="\340">\340</span> <span class="token entity" title="\205">\205</span><span class="token entity" title="\a">\a</span>墭<span class="token entity" title="\240">\240</span>ZЯ<span class="token entity" title="\266">\266</span><span class="token entity" title="\330">\330</span> <span class="token entity" title="\335">\335</span><span class="token entity" title="\334">\334</span><span class="token entity" title="\314">\314</span>ё<span class="token entity" title="\255">\255</span><span class="token entity" title="\262">\262</span>a+N<span class="token entity" title="\367">\367</span><span class="token entity" title="\021">\021</span><span class="token entity" title="\214">\214</span><span class="token entity" title="\322">\322</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\021">\021</span>)<span class="token entity" title="\356">\356</span><span class="token entity" title="\362">\362</span>=<span class="token entity" title="\201">\201</span><span class="token entity" title="\310">\310</span><span class="token entity" title="\354">\354</span><span class="token entity" title="\005">\005</span><span class="token entity" title="\273">\273</span>o<span class="token entity" title="\250">\250</span>a)$<span class="token entity" title="\254">\254</span>z<span class="token entity" title="\226">\226</span><span class="token entity" title="\371">\371</span><span class="token entity" title="\322">\322</span><span class="token entity" title="\003">\003</span>n<span class="token entity" title="\241">\241</span><span class="token entity" title="\244">\244</span>Z<span class="token entity" title="\032">\032</span><span class="token entity" title="\277">\277</span><span class="token entity" title="\217">\217</span><span class="token entity" title="\060">\060</span><span class="token entity" title="\225">\225</span><span class="token entity" title="\353">\353</span>.<span class="token entity" title="\276">\276</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\206">\206</span>;<span class="token entity" title="\245">\245</span>Ȩ<span class="token entity" title="\245">\245</span><span class="token entity" title="\211">\211</span>㓫<span class="token entity" title="\326">\326</span><span class="token entity" title="\313">\313</span><span class="token entity" title="\370">\370</span>V<span class="token entity" title="\360">\360</span><span class="token entity" title="\327">\327</span><span class="token entity" title="\t">\t</span><span class="token entity" title="\310">\310</span>RX<span class="token entity" title="\362">\362</span><span class="token entity" title="\026">\026</span>P<span class="token entity" title="\223">\223</span><span class="token entity" title="\302">\302</span><span class="token entity" title="\032">\032</span><span class="token entity" title="\027">\027</span><span class="token entity" title="\351">\351</span><span class="token entity" title="\067">\067</span><span class="token entity" title="\003">\003</span>|<span class="token entity" title="\034">\034</span><span class="token entity" title="\024">\024</span><span class="token entity" title="\r">\r</span><span class="token entity" title="\021">\021</span>R<span class="token entity" title="\233">\233</span><span class="token entity" title="\334">\334</span>R=<span class="token entity" title="\376">\376</span>&amp;<span class="token entity" title="\022">\022</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\235">\235</span><span class="token entity" title="\033">\033</span><span class="token entity" title="\313">\313</span><span class="token entity" title="\315">\315</span><span class="token entity" title="\361">\361</span>mW&quot;</span>, <span class="token operator">&lt;</span>incomplete sequence <span class="token punctuation">\</span><span class="token number">31</span><span class="token operator"><span class="token file-descriptor important">0</span>&gt;</span><span class="token punctuation">..</span>., <span class="token variable assign-left">in_sz</span><span class="token operator">=</span><span class="token number">976</span>, <span class="token variable assign-left">in2</span><span class="token operator">=</span>0x7fffffffa910 <span class="token string">&quot;<span class="token entity" title="\001">\001</span>&quot;</span>, <span class="token variable assign-left">in2_sz</span><span class="token operator">=</span><span class="token number">4</span>, <span class="token variable assign-left">out</span><span class="token operator">=</span>0x227a99f925e8 <span class="token string">&quot;&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"> at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:18404 </span><span class="code-line"><span class="token comment">#4 0x00007fffd1ab03aa in sqlcipher_page_hmac</span> </span><span class="code-line"> <span class="token punctuation">(</span>out<span class="token operator">=</span>0x227a99f925e8 <span class="token string">&quot;&quot;</span>, <span class="token variable assign-left">in_sz</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, <span class="token variable assign-left">in</span><span class="token operator">=</span>0x227a9a00b548 <span class="token string">&quot;<span class="token entity" title="\250">\250</span><span class="token entity" title="\235">\235</span>J_h1E<span class="token entity" title="\214">\214</span><span class="token entity" title="\v">\v</span><span class="token entity" title="\033">\033</span>u<span class="token entity" title="\266">\266</span><span class="token entity" title="\342">\342</span>P.<span class="token entity" title="\240">\240</span><span class="token entity" title="\063">\063</span><span class="token entity" title="\244">\244</span><span class="token entity" title="\337">\337</span>V<span class="token entity" title="\313">\313</span><span class="token entity" title="\360">\360</span>T<span class="token entity" title="\r">\r</span>qu&lt;c:<span class="token entity" title="\303">\303</span>E<span class="token entity" title="\234">\234</span><span class="token entity" title="\061">\061</span>-<span class="token entity" title="\216">\216</span><span class="token entity" title="\365">\365</span><span class="token entity" title="\255">\255</span><span class="token entity" title="\033">\033</span>Dz<span class="token entity" title="\203">\203</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\027">\027</span><span class="token entity" title="\257">\257</span><span class="token entity" title="\215">\215</span><span class="token entity" title="\033">\033</span><span class="token entity" title="\070">\070</span>{i9H<span class="token entity" title="\376">\376</span><span class="token entity" title="\346">\346</span>H<span class="token entity" title="\223">\223</span>DB<span class="token entity" title="\244">\244</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\314">\314</span>d<span class="token entity" title="\302">\302</span><span class="token entity" title="\022">\022</span><span class="token entity" title="\310">\310</span><span class="token entity" title="\376">\376</span><span class="token entity" title="\315">\315</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\343">\343</span><span class="token entity" title="\&quot;">\&quot;</span><span class="token entity" title="\362">\362</span>e<span class="token entity" title="\227">\227</span><span class="token entity" title="\252">\252</span>T<span class="token entity" title="\363">\363</span><span class="token entity" title="\215">\215</span><span class="token entity" title="\351">\351</span><span class="token entity" title="\323">\323</span><span class="token entity" title="\005">\005</span><span class="token entity" title="\271">\271</span><span class="token entity" title="\022">\022</span>ǎ<span class="token entity" title="\340">\340</span> <span class="token entity" title="\205">\205</span><span class="token entity" title="\a">\a</span>墭<span class="token entity" title="\240">\240</span>ZЯ<span class="token entity" title="\266">\266</span><span class="token entity" title="\330">\330</span> <span class="token entity" title="\335">\335</span><span class="token entity" title="\334">\334</span><span class="token entity" title="\314">\314</span>ё<span class="token entity" title="\255">\255</span><span class="token entity" title="\262">\262</span>a+N<span class="token entity" title="\367">\367</span><span class="token entity" title="\021">\021</span><span class="token entity" title="\214">\214</span><span class="token entity" title="\322">\322</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\021">\021</span>)<span class="token entity" title="\356">\356</span><span class="token entity" title="\362">\362</span>=<span class="token entity" title="\201">\201</span><span class="token entity" title="\310">\310</span><span class="token entity" title="\354">\354</span><span class="token entity" title="\005">\005</span><span class="token entity" title="\273">\273</span>o<span class="token entity" title="\250">\250</span>a)$<span class="token entity" title="\254">\254</span>z<span class="token entity" title="\226">\226</span><span class="token entity" title="\371">\371</span><span class="token entity" title="\322">\322</span><span class="token entity" title="\003">\003</span>n<span class="token entity" title="\241">\241</span><span class="token entity" title="\244">\244</span>Z<span class="token entity" title="\032">\032</span><span class="token entity" title="\277">\277</span><span class="token entity" title="\217">\217</span><span class="token entity" title="\060">\060</span><span class="token entity" title="\225">\225</span><span class="token entity" title="\353">\353</span>.<span class="token entity" title="\276">\276</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\206">\206</span>;<span class="token entity" title="\245">\245</span>Ȩ<span class="token entity" title="\245">\245</span><span class="token entity" title="\211">\211</span>㓫<span class="token entity" title="\326">\326</span><span class="token entity" title="\313">\313</span><span class="token entity" title="\370">\370</span>V<span class="token entity" title="\360">\360</span><span class="token entity" title="\327">\327</span><span class="token entity" title="\t">\t</span><span class="token entity" title="\310">\310</span>RX<span class="token entity" title="\362">\362</span><span class="token entity" title="\026">\026</span>P<span class="token entity" title="\223">\223</span><span class="token entity" title="\302">\302</span><span class="token entity" title="\032">\032</span><span class="token entity" title="\027">\027</span><span class="token entity" title="\351">\351</span><span class="token entity" title="\067">\067</span><span class="token entity" title="\003">\003</span>|<span class="token entity" title="\034">\034</span><span class="token entity" title="\024">\024</span><span class="token entity" title="\r">\r</span><span class="token entity" title="\021">\021</span>R<span class="token entity" title="\233">\233</span><span class="token entity" title="\334">\334</span>R=<span class="token entity" title="\376">\376</span>&amp;<span class="token entity" title="\022">\022</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\235">\235</span><span class="token entity" title="\033">\033</span><span class="token entity" title="\313">\313</span><span class="token entity" title="\315">\315</span><span class="token entity" title="\361">\361</span>mW&quot;</span>, <span class="token operator">&lt;</span>incomplete sequence <span class="token punctuation">\</span><span class="token number">31</span><span class="token operator"><span class="token file-descriptor important">0</span>&gt;</span><span class="token punctuation">..</span>., <span class="token variable assign-left">pgno</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, <span class="token variable assign-left">ctx</span><span class="token operator">=</span>0x227a99d3f078<span class="token punctuation">)</span> at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:17506 </span><span class="code-line"><span class="token comment">#5 sqlcipher_page_cipher</span> </span><span class="code-line"> <span class="token punctuation">(</span>ctx<span class="token operator">=</span>ctx@entry<span class="token operator">=</span>0x227a99d095a8, <span class="token variable assign-left">for_ctx</span><span class="token operator">=</span>for_ctx@entry<span class="token operator">=</span><span class="token number">0</span>, <span class="token variable assign-left">pgno</span><span class="token operator">=</span><span class="token operator">&lt;</span>optimized out<span class="token operator">&gt;</span>, <span class="token variable assign-left">mode</span><span class="token operator">=</span>mode@entry<span class="token operator">=</span><span class="token number">0</span>, <span class="token variable assign-left">page_sz</span><span class="token operator">=</span><span class="token number">1008</span>, <span class="token variable assign-left">in</span><span class="token operator">=</span>0x227a9a00b548 <span class="token string">&quot;<span class="token entity" title="\250">\250</span><span class="token entity" title="\235">\235</span>J_h1E<span class="token entity" title="\214">\214</span><span class="token entity" title="\v">\v</span><span class="token entity" title="\033">\033</span>u<span class="token entity" title="\266">\266</span><span class="token entity" title="\342">\342</span>P.<span class="token entity" title="\240">\240</span><span class="token entity" title="\063">\063</span><span class="token entity" title="\244">\244</span><span class="token entity" title="\337">\337</span>V<span class="token entity" title="\313">\313</span><span class="token entity" title="\360">\360</span>T<span class="token entity" title="\r">\r</span>qu&lt;c:<span class="token entity" title="\303">\303</span>E<span class="token entity" title="\234">\234</span><span class="token entity" title="\061">\061</span>-<span class="token entity" title="\216">\216</span><span class="token entity" title="\365">\365</span><span class="token entity" title="\255">\255</span><span class="token entity" title="\033">\033</span>Dz<span class="token entity" title="\203">\203</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\027">\027</span><span class="token entity" title="\257">\257</span><span class="token entity" title="\215">\215</span><span class="token entity" title="\033">\033</span><span class="token entity" title="\070">\070</span>{i9H<span class="token entity" title="\376">\376</span><span class="token entity" title="\346">\346</span>H<span class="token entity" title="\223">\223</span>DB<span class="token entity" title="\244">\244</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\314">\314</span>d<span class="token entity" title="\302">\302</span><span class="token entity" title="\022">\022</span><span class="token entity" title="\310">\310</span><span class="token entity" title="\376">\376</span><span class="token entity" title="\315">\315</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\343">\343</span><span class="token entity" title="\&quot;">\&quot;</span><span class="token entity" title="\362">\362</span>e<span class="token entity" title="\227">\227</span><span class="token entity" title="\252">\252</span>T<span class="token entity" title="\363">\363</span><span class="token entity" title="\215">\215</span><span class="token entity" title="\351">\351</span><span class="token entity" title="\323">\323</span><span class="token entity" title="\005">\005</span><span class="token entity" title="\271">\271</span><span class="token entity" title="\022">\022</span>ǎ<span class="token entity" title="\340">\340</span> <span class="token entity" title="\205">\205</span><span class="token entity" title="\a">\a</span>墭<span class="token entity" title="\240">\240</span>ZЯ<span class="token entity" title="\266">\266</span><span class="token entity" title="\330">\330</span> <span class="token entity" title="\335">\335</span><span class="token entity" title="\334">\334</span><span class="token entity" title="\314">\314</span>ё<span class="token entity" title="\255">\255</span><span class="token entity" title="\262">\262</span>a+N<span class="token entity" title="\367">\367</span><span class="token entity" title="\021">\021</span><span class="token entity" title="\214">\214</span><span class="token entity" title="\322">\322</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\021">\021</span>)<span class="token entity" title="\356">\356</span><span class="token entity" title="\362">\362</span>=<span class="token entity" title="\201">\201</span><span class="token entity" title="\310">\310</span><span class="token entity" title="\354">\354</span><span class="token entity" title="\005">\005</span><span class="token entity" title="\273">\273</span>o<span class="token entity" title="\250">\250</span>a)$<span class="token entity" title="\254">\254</span>z<span class="token entity" title="\226">\226</span><span class="token entity" title="\371">\371</span><span class="token entity" title="\322">\322</span><span class="token entity" title="\003">\003</span>n<span class="token entity" title="\241">\241</span><span class="token entity" title="\244">\244</span>Z<span class="token entity" title="\032">\032</span><span class="token entity" title="\277">\277</span><span class="token entity" title="\217">\217</span><span class="token entity" title="\060">\060</span><span class="token entity" title="\225">\225</span><span class="token entity" title="\353">\353</span>.<span class="token entity" title="\276">\276</span><span class="token entity" title="\001">\001</span><span class="token entity" title="\206">\206</span>;<span class="token entity" title="\245">\245</span>Ȩ<span class="token entity" title="\245">\245</span><span class="token entity" title="\211">\211</span>㓫<span class="token entity" title="\326">\326</span><span class="token entity" title="\313">\313</span><span class="token entity" title="\370">\370</span>V<span class="token entity" title="\360">\360</span><span class="token entity" title="\327">\327</span><span class="token entity" title="\t">\t</span><span class="token entity" title="\310">\310</span>RX<span class="token entity" title="\362">\362</span><span class="token entity" title="\026">\026</span>P<span class="token entity" title="\223">\223</span><span class="token entity" title="\302">\302</span><span class="token entity" title="\032">\032</span><span class="token entity" title="\027">\027</span><span class="token entity" title="\351">\351</span><span class="token entity" title="\067">\067</span><span class="token entity" title="\003">\003</span>|<span class="token entity" title="\034">\034</span><span class="token entity" title="\024">\024</span><span class="token entity" title="\r">\r</span><span class="token entity" title="\021">\021</span>R<span class="token entity" title="\233">\233</span><span class="token entity" title="\334">\334</span>R=<span class="token entity" title="\376">\376</span>&amp;<span class="token entity" title="\022">\022</span><span class="token entity" title="\b">\b</span><span class="token entity" title="\235">\235</span><span class="token entity" title="\033">\033</span><span class="token entity" title="\313">\313</span><span class="token entity" title="\315">\315</span><span class="token entity" title="\361">\361</span>mW&quot;</span>, <span class="token operator">&lt;</span>incomplete sequence <span class="token punctuation">\</span><span class="token number">31</span><span class="token operator"><span class="token file-descriptor important">0</span>&gt;</span><span class="token punctuation">..</span>., <span class="token variable assign-left">out</span><span class="token operator">=</span>0x227a99f92218 <span class="token string">&quot;&quot;</span><span class="token punctuation">)</span> at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:17556 </span><span class="code-line"><span class="token comment">#6 0x00007fffd1ac1a84 in sqlite3Codec (iCtx=0x227a99d095a8, data=0x227a9a00b538, pgno=1, mode=3) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:16249</span> </span><span class="code-line"><span class="token comment">#7 0x00007fffd1a93595 in readDbPage (pPg=pPg@entry=0x227a9a00b970, iFrame=&lt;optimized out&gt;) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:50416</span> </span><span class="code-line"><span class="token comment">#8 0x00007fffd1adf61e in sqlite3PagerGet (pPager=0x227a99f44008, pgno=pgno@entry=1, ppPage=ppPage@entry=0x7fffffffaa68, flags=flags@entry=0)</span> </span><span class="code-line"> at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:52923 </span><span class="code-line"><span class="token comment">#9 0x00007fffd1ae1d08 in btreeGetPage (flags=0, ppPage=&lt;synthetic pointer&gt;, pgno=1, pBt=0x227a99fb3648) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:60539</span> </span><span class="code-line"><span class="token comment">#10 lockBtree (pBt=pBt@entry=0x227a99fb3648) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:61441</span> </span><span class="code-line"><span class="token comment">#11 0x00007fffd1ae5af0 in sqlite3BtreeBeginTrans (p=0x227a99d683c8, wrflag=0) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:61799</span> </span><span class="code-line"><span class="token comment">#12 0x00007fffd1b17fe8 in sqlite3InitOne (db=db@entry=0x227a99f67e08, iDb=iDb@entry=0, pzErrMsg=pzErrMsg@entry=0x227a99c81090) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:112652</span> </span><span class="code-line"><span class="token comment">#13 0x00007fffd1b1822c in sqlite3Init (db=db@entry=0x227a99f67e08, pzErrMsg=pzErrMsg@entry=0x227a99c81090) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:112831</span> </span><span class="code-line"><span class="token comment">#14 0x00007fffd1b1a098 in sqlite3ReadSchema (pParse=0x227a99c81088) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:112868</span> </span><span class="code-line"><span class="token comment">#15 sqlite3LocateTable (pParse=0x227a99c81088, isView=0, zName=0x227a99fea708 &quot;sqlite_master&quot;, zDbase=0x0) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:32141</span> </span><span class="code-line"><span class="token comment">#16 0x00007fffd1b1a84a in selectExpander (pWalker=0x7fffffffadb0, p=0x227a99fea208) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:117593</span> </span><span class="code-line"><span class="token comment">#17 0x00007fffd1aa2e02 in sqlite3WalkSelect (pWalker=pWalker@entry=0x7fffffffadb0, p=p@entry=0x227a99fea208) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:87991</span> </span><span class="code-line"><span class="token comment">#18 0x00007fffd1aa327f in sqlite3WalkSelect (p=0x227a99fea208, pWalker=0x7fffffffadb0) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:87988</span> </span><span class="code-line"><span class="token comment">#19 sqlite3SelectExpand (pSelect=0x227a99fea208, pParse=0x227a99c81088) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:52306</span> </span><span class="code-line"><span class="token comment">#20 sqlite3SelectPrep (pParse=0x227a99c81088, p=0x227a99fea208, pOuterNC=0x0) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:52392</span> </span><span class="code-line"><span class="token comment">#21 0x00007fffd1af7762 in sqlite3Select (pParse=pParse@entry=0x227a99c81088, p=0x227a99fea208, pDest=pDest@entry=0x7fffffffb0e0) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:118172</span> </span><span class="code-line"><span class="token comment">#22 0x00007fffd1b1250d in yy_reduce (yyruleno=111, yypParser=0x227a99abe708) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:133385</span> </span><span class="code-line"><span class="token comment">#23 sqlite3Parser (yyp=yyp@entry=0x227a99abe708, yymajor=yymajor@entry=1, yyminor=..., pParse=pParse@entry=0x227a99c81088) at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:3399</span> </span><span class="code-line"><span class="token comment">#24 0x00007fffd1b15fbe in sqlite3RunParser</span> </span><span class="code-line"> <span class="token punctuation">(</span>pParse<span class="token operator">=</span>pParse@entry<span class="token operator">=</span>0x227a99c81088, <span class="token variable assign-left">zSql</span><span class="token operator">=</span>zSql@entry<span class="token operator">=</span>0x7fffd1b3c178 <span class="token string">&quot;SELECT name FROM sqlite_master WHERE type=&#x27;table&#x27; AND name=:tbl_name&quot;</span>, <span class="token variable assign-left">pzErrMsg</span><span class="token operator">=</span>pzErrMsg@entry<span class="token operator">=</span>0x7fffffffb1f8<span class="token punctuation">)</span> </span><span class="code-line"> at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:135410 </span><span class="code-line"><span class="token comment">#25 0x00007fffd1b169a9 in sqlite3Prepare</span> </span><span class="code-line"> <span class="token punctuation">(</span>db<span class="token operator">=</span>db@entry<span class="token operator">=</span>0x227a99f67e08, <span class="token variable assign-left">zSql</span><span class="token operator">=</span>zSql@entry<span class="token operator">=</span>0x7fffd1b3c178 <span class="token string">&quot;SELECT name FROM sqlite_master WHERE type=&#x27;table&#x27; AND name=:tbl_name&quot;</span>, <span class="token variable assign-left">nBytes</span><span class="token operator">=</span>nBytes@entry<span class="token operator">=</span>-1, <span class="token variable assign-left">saveSqlFlag</span><span class="token operator">=</span>saveSqlFlag@entry<span class="token operator">=</span><span class="token number">1</span>, <span class="token variable assign-left">pReprepare</span><span class="token operator">=</span>pReprepare@entry<span class="token operator">=</span>0x0, <span class="token variable assign-left">ppStmt</span><span class="token operator">=</span>ppStmt@entry<span class="token operator">=</span>0x7fffffffb378, <span class="token variable assign-left">pzTail</span><span class="token operator">=</span>0x0<span class="token punctuation">)</span> at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:113061 </span><span class="code-line"><span class="token comment">#26 0x00007fffd1b16ea0 in sqlite3LockAndPrepare</span> </span><span class="code-line"> <span class="token punctuation">(</span>db<span class="token operator">=</span>0x227a99f67e08, <span class="token variable assign-left">zSql</span><span class="token operator">=</span>0x7fffd1b3c178 <span class="token string">&quot;SELECT name FROM sqlite_master WHERE type=&#x27;table&#x27; AND name=:tbl_name&quot;</span>, <span class="token variable assign-left">nBytes</span><span class="token operator">=</span>-1, <span class="token variable assign-left">saveSqlFlag</span><span class="token operator">=</span><span class="token number">1</span>, <span class="token variable assign-left">pOld</span><span class="token operator">=</span>0x0, <span class="token variable assign-left">ppStmt</span><span class="token operator">=</span>0x7fffffffb378, <span class="token variable assign-left">pzTail</span><span class="token operator">=</span>0x0<span class="token punctuation">)</span> </span><span class="code-line"> at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:113153 </span><span class="code-line"><span class="token comment">#27 0x00007fffd1b173b6 in sqlite3_prepare_v2 (db=&lt;optimized out&gt;, zSql=&lt;optimized out&gt;, nBytes=&lt;optimized out&gt;, ppStmt=&lt;optimized out&gt;, pzTail=&lt;optimized out&gt;)</span> </span><span class="code-line"><span class="token variable parameter">--Type</span> <span class="token operator">&lt;</span>RET<span class="token operator">&gt;</span> <span class="token keyword">for</span> more, q to quit, c to <span class="token builtin class-name">continue</span> without paging--c </span><span class="code-line"> at /home/neokylinv7/桌面/SourceCode/mazu/source/sqlcipher/sqlite3.c:113229 </span><span class="code-line"><span class="token comment">#28 0x00007fffd185cf6d in baiduyun::minos::database::SqliteStatement::prepare(char const*) (this=this@entry=0x7fffffffb360, sql=sql@entry=0x7fffd1b3c178 &quot;SELECT name FROM sqlite_master WHERE type=&#x27;table&#x27; AND name=:tbl_name&quot;) at /home/neokylinv7/桌面/SourceCode/mazu/source/kernel/base/database_statement.cpp:34</span> </span><span class="code-line"><span class="token comment">#29 0x00007fffd185c3e5 in baiduyun::minos::database::SqliteConnection::table_existed(char const*) (this=&lt;optimized out&gt;, table_name=table_name@entry=0x7fffd1b983f2 &quot;version&quot;) at /home/neokylinv7/桌面/SourceCode/mazu/source/kernel/base/database_connection.cpp:134</span> </span><span class="code-line"><span class="token comment">#30 0x00007fffd18b0bde in baiduyun::minos::database::TransmitDataInstance::initialize(char const*, baiduyun::minos::database::SqliteEncrytKeys const&amp;) (this=0x227a999be900, path=0x227a99d3f0f8 &quot;/home/ttys3/.config/baidunetdisk/AppData/at_trche&quot;, encrypt_keys=...) at /home/neokylinv7/桌面/SourceCode/mazu/source/kernel/persist/transmit_data_instance.cpp:74</span> </span><span class="code-line"><span class="token comment">#31 0x00007fffd185f431 in baiduyun::minos::log::LogController::initialize(char const*, baiduyun::minos::database::SqliteEncrytKeys const&amp;) (this=0x227a99d4e3c0, config=config@entry=0x227a995bbe98 &quot;{\&quot;root\&quot;:\&quot;\\/home\\/ttys3\\/.config\\/baidunetdisk\\/AppData\\/\&quot;,\&quot;name\&quot;:\&quot;at\&quot;,\&quot;use_default_key\&quot;:\&quot;1\&quot;}\n&quot;, encrypt_keys=...) at /home/neokylinv7/桌面/SourceCode/mazu/source/kernel/log/log_controller.cpp:109</span> </span><span class="code-line"><span class="token comment">#32 0x00007fffd1848f79 in (anonymous namespace)::logcontroller_initialize (encrypt_keys=..., config=0x227a995bbe98 &quot;{\&quot;root\&quot;:\&quot;\\/home\\/ttys3\\/.config\\/baidunetdisk\\/AppData\\/\&quot;,\&quot;name\&quot;:\&quot;at\&quot;,\&quot;use_default_key\&quot;:\&quot;1\&quot;}\n&quot;) at /home/neokylinv7/桌面/SourceCode/mazu/source/kernel/minos-agent.cpp:47</span> </span><span class="code-line"><span class="token comment">#33 minos_agent_global_init(char const*, void const*, int, void const*, int) (config=0x227a995bbe98 &quot;{\&quot;root\&quot;:\&quot;\\/home\\/ttys3\\/.config\\/baidunetdisk\\/AppData\\/\&quot;,\&quot;name\&quot;:\&quot;at\&quot;,\&quot;use_default_key\&quot;:\&quot;1\&quot;}\n&quot;, encrypt_key=&lt;optimized out&gt;, key_len=&lt;optimized out&gt;, encrypt_newkey=0x0, newkey_len=&lt;optimized out&gt;) at /home/neokylinv7/桌面/SourceCode/mazu/source/kernel/minos-agent.cpp:141</span> </span><span class="code-line"><span class="token comment">#34 0x00007fffe08e5008 in baidu::netdisk::sdk::sdk_minos_init (newkey_len=0, encrypt_newkey=0x0, key_len=0, encrypt_key=0x0, config=0x227a995bbe98 &quot;{\&quot;root\&quot;:\&quot;\\/home\\/ttys3\\/.config\\/baidunetdisk\\/AppData\\/\&quot;,\&quot;name\&quot;:\&quot;at\&quot;,\&quot;use_default_key\&quot;:\&quot;1\&quot;}\n&quot;) at /home/common/桌面/project/browserengine/source/browserengine/sdk/minosagent/minos_wrapper.h:32</span> </span><span class="code-line"><span class="token comment">#35 baidu::netdisk::sdk::MinosConfigManager::init_minos(std::string const&amp;) (this=this@entry=0x7fffffffbc5e, app_path=&quot;/home/ttys3/.config/baidunetdisk&quot;) at /home/common/桌面/project/browserengine/source/browserengine/sdk/minosagent/minos_config_manager.cpp:61</span> </span><span class="code-line"><span class="token comment">#36 0x00007fffe0731c87 in browser_engine_global_init(browser_engine_internal_log_callback, browser_engine_common_event_callback) (log_callback=&lt;optimized out&gt;, event_callback=&lt;optimized out&gt;) at /home/common/桌面/project/browserengine/source/browserengine/browser_engine.cpp:144</span> </span><span class="code-line"><span class="token comment">#37 0x00007ffff6159b10 in ffi_call_unix64 () at /lib64/libffi.so.6</span> </span><span class="code-line"><span class="token comment">#38 0x00007ffff61590a3 in ffi_call () at /lib64/libffi.so.6</span> </span><span class="code-line"><span class="token comment">#39 0x00007fffe0f927f9 in FFI::FFICall(Nan::FunctionCallbackInfo&lt;v8::Value&gt; const&amp;) () at /tmp/.org.chromium.Chromium.gNqpPK</span> </span><span class="code-line"><span class="token comment">#40 0x00007fffe0f925a6 in Nan::imp::FunctionCallbackWrapper(v8::FunctionCallbackInfo&lt;v8::Value&gt; const&amp;) () at /tmp/.org.chromium.Chromium.gNqpPK</span> </span><span class="code-line"><span class="token comment">#41 0x0000555557cdc6d7 in ()</span> </span></code></pre></div><p>目测翻车在<code>libcrypto.so.1.1</code>, 而且是跟sqlite加密有关.</p><p>我们把baidunetdisk动态链接到相关的加密库都找出来:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ ldd baidunetdisk <span class="token operator">|</span> <span class="token function">grep</span> <span class="token variable parameter">-i</span> <span class="token variable parameter">-E</span> <span class="token string">&#x27;ssl|crypt&#x27;</span> </span><span class="code-line"> libgcrypt.so.20 <span class="token operator">=</span><span class="token operator">&gt;</span> /lib64/libgcrypt.so.20 <span class="token punctuation">(</span>0x00007fa18d693000<span class="token punctuation">)</span> </span><span class="code-line"> libk5crypto.so.3 <span class="token operator">=</span><span class="token operator">&gt;</span> /lib64/libk5crypto.so.3 <span class="token punctuation">(</span>0x00007fa18d3cd000<span class="token punctuation">)</span> </span><span class="code-line"> libcrypto.so.1.1 <span class="token operator">=</span><span class="token operator">&gt;</span> /lib64/libcrypto.so.1.1 <span class="token punctuation">(</span>0x00007fa18d0c0000<span class="token punctuation">)</span> </span></code></pre></div><p>经验告诉我,这个baidunetdisk挂的原因是, Fedora 33上面的包都比较新,尤其是 openssl 库. 因此,解决办法是,去下载老版本的 Ubuntu 18.04 的包,然后把so文件取出来,强制baidunetdisk使用这些旧版本的库即可.</p><p><code>ldd</code> 一下很容易找出依赖关系: <code>libkrb5.so.3</code> -&gt; <code>libk5crypto.so.3</code> -&gt; <code>libcrypto.so.1.1</code></p><p>老灯下载了以下包:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token literal-property property">https</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>ubuntu<span class="token punctuation">.</span><span class="token property-access">pkgs</span><span class="token punctuation">.</span><span class="token property-access">org</span><span class="token operator">/</span><span class="token number">18.04</span><span class="token operator">/</span>ubuntu<span class="token operator">-</span>main<span class="token operator">-</span>amd64<span class="token operator">/</span>libkrb5support0_1<span class="token punctuation">.</span><span class="token number">16</span><span class="token operator">-</span>2build1_amd64<span class="token punctuation">.</span><span class="token property-access">deb</span><span class="token punctuation">.</span><span class="token property-access">html</span> </span><span class="code-line"><span class="token literal-property property">https</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>ubuntu<span class="token punctuation">.</span><span class="token property-access">pkgs</span><span class="token punctuation">.</span><span class="token property-access">org</span><span class="token operator">/</span><span class="token number">18.04</span><span class="token operator">/</span>ubuntu<span class="token operator">-</span>main<span class="token operator">-</span>amd64<span class="token operator">/</span>libk5crypto3_1<span class="token punctuation">.</span><span class="token number">16</span><span class="token operator">-</span>2build1_amd64<span class="token punctuation">.</span><span class="token property-access">deb</span><span class="token punctuation">.</span><span class="token property-access">html</span> </span><span class="code-line"><span class="token literal-property property">https</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>ubuntu<span class="token punctuation">.</span><span class="token property-access">pkgs</span><span class="token punctuation">.</span><span class="token property-access">org</span><span class="token operator">/</span><span class="token number">18.04</span><span class="token operator">/</span>ubuntu<span class="token operator">-</span>main<span class="token operator">-</span>amd64<span class="token operator">/</span>libkrb5<span class="token operator">-</span><span class="token number">3_1.16</span><span class="token operator">-</span>2build1_amd64<span class="token punctuation">.</span><span class="token property-access">deb</span><span class="token punctuation">.</span><span class="token property-access">html</span> </span><span class="code-line"><span class="token literal-property property">https</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>ubuntu<span class="token punctuation">.</span><span class="token property-access">pkgs</span><span class="token punctuation">.</span><span class="token property-access">org</span><span class="token operator">/</span><span class="token number">18.04</span><span class="token operator">/</span>ubuntu<span class="token operator">-</span>main<span class="token operator">-</span>amd64<span class="token operator">/</span>libgssapi<span class="token operator">-</span>krb5<span class="token operator">-</span><span class="token number">2_1.16</span><span class="token operator">-</span>2build1_amd64<span class="token punctuation">.</span><span class="token property-access">deb</span><span class="token punctuation">.</span><span class="token property-access">html</span> </span><span class="code-line"><span class="token literal-property property">http</span><span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>archive<span class="token punctuation">.</span><span class="token property-access">ubuntu</span><span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">/</span>ubuntu<span class="token operator">/</span>pool<span class="token operator">/</span>main<span class="token operator">/</span>o<span class="token operator">/</span>openssl<span class="token operator">/</span>libssl1<span class="token punctuation">.</span><span class="token number">1_1.1</span><span class="token punctuation">.</span>0g<span class="token operator">-</span>2ubuntu4_amd64<span class="token punctuation">.</span><span class="token property-access">deb</span> </span></code></pre></div><p>测试下, krb 的包已经成功加载:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">env</span> <span class="token variable assign-left">LD_LIBRARY_PATH</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token builtin class-name">pwd</span><span class="token variable">)</span></span> ldd ./baidunetdisk <span class="token operator">|</span> <span class="token function">grep</span> /opt/ </span><span class="code-line"> libffmpeg.so <span class="token operator">=</span><span class="token operator">&gt;</span> /opt/baidunetdisk/./libffmpeg.so <span class="token punctuation">(</span>0x00007f8fc36a8000<span class="token punctuation">)</span> </span><span class="code-line"> libgssapi_krb5.so.2 <span class="token operator">=</span><span class="token operator">&gt;</span> /opt/baidunetdisk/./libgssapi_krb5.so.2 <span class="token punctuation">(</span>0x00007f8fc1588000<span class="token punctuation">)</span> </span><span class="code-line"> libkrb5.so.3 <span class="token operator">=</span><span class="token operator">&gt;</span> /opt/baidunetdisk/./libkrb5.so.3 <span class="token punctuation">(</span>0x00007f8fc0bf4000<span class="token punctuation">)</span> </span><span class="code-line"> libk5crypto.so.3 <span class="token operator">=</span><span class="token operator">&gt;</span> /opt/baidunetdisk/./libk5crypto.so.3 <span class="token punctuation">(</span>0x00007f8fc09c2000<span class="token punctuation">)</span> </span><span class="code-line"> libkrb5support.so.0 <span class="token operator">=</span><span class="token operator">&gt;</span> /opt/baidunetdisk/./libkrb5support.so.0 <span class="token punctuation">(</span>0x00007f8fc07af000<span class="token punctuation">)</span> </span></code></pre></div><p>编辑 <code>/usr/share/applications/baidunetdisk.desktop</code>, 将<code>Exec=/opt/baidunetdisk/baidunetdisk --no-sandbox %U</code> 修改成:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token variable assign-left">Exec</span><span class="token operator">=</span>/bin/env <span class="token variable assign-left">LD_LIBRARY_PATH</span><span class="token operator">=</span>/home/ttys3/Apps/baidunetdisk /home/ttys3/Apps/baidunetdisk/baidunetdisk --no-sandbox %U </span></code></pre></div><p>注意,这里老灯把baidu的目录放在/home/ttys3/Apps/baidunetdisk, 测试过程中发现放在默认的 <code>/opt/baidunetdisk</code> 无法成功运行(有可能跟selinux有关,暂时没空看了,解决了问题完事)。</p><div><img alt="baidunetdisk-fedora33-2020-12-20_21-53.png" src="https://ttys3.dev/static/assets/baidunetdisk-fedora33-2020-12-20_21-53-RO72BWR7.png" title="baidunetdisk-fedora33-2020-12-20_21-53.png" width="2084" height="1224"/></div> Sun, 20 Dec 2020 13:24:50 GMT ttyS3 Fedorabaidunetdisk https://ttys3.dev/blog/systemd-resolved-the-default-dns-resolver-in-fedora-33 Fedora 33 中的 systemd-resolved DNS resolver https://ttys3.dev/blog/systemd-resolved-the-default-dns-resolver-in-fedora-33 <p>Fedora 33 中的 DNS resolver 已经由 <code>nss-dns</code> 默认切换成了 <a href="https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html">systemd-resolved</a> 简单来说,这意味着 <code>systemd-resolved</code> 将作为daemon程序运行。所有想要将域名转换为网络地址的程序都将与之通信。 这取代了当前默认的查找机制--每个程序单独与远程服务器交谈,并且没有共享缓存。</p><p>如有必要, <code>systemd-resolved</code> 将查询远程DNS服务器。 <code>systemd-resolved</code> 是一个“stub resolver” - 它本身不会解析任何域名(通过从根DNS开始并按标签一路径往下查询),而是将查询转发到远程DNS服务器。 其实这种类型的程序我们经常用,比如我们通常用的路由器上一般会用 <code>dnsmasq</code> 做“stub resolver”, 其下的局域网机器,通过DHCP自动获取到DNS后通常是这个路由器自己的LAN IP, 比如常见的 192.168.1.1 等。<code>dnsmasq</code> 自带缓存功能,也就是说一个域名已经解析过了,它不会每次都需要通过与远程DNS服务器通信来解析,而是可以在命中缓存结果的情况下直接返回。 <code>systemd-resolved</code> 的引入,相当于每台 Linux 机器本身已经有了一个类似 <code>dnsmasq</code> 的东西在跑。同时,每台机器对于跑在上面的程序的DNS查询配置,可以更加灵活了(因为split DNS)。</p><p>单个daemon程序处理域名解析提供了显著的好处。由于daemon进程会缓存响应结果,因而可以快速响应高频请求的域名。守护进程记得哪些服务器是非响应的,而预先每个程序都必须在超时后自己弄清楚这一点。个别程序仅在本地传输上与守护程序交谈,并从网络中孤立。守护程序支持花哨的规则,该规则指定应使用哪些名称服务器用于哪些域名 - 事实上,本文的其余部分是关于这些规则。</p><h2 id="技术相关"><a href="#技术相关" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>技术相关</h2><p>来自 <a href="https://fedoraproject.org/wiki/Changes/systemd-resolved#Detailed_Description">https://fedoraproject.org/wiki/Changes/systemd-resolved#Detailed_Description</a></p><blockquote><p>Enable systemd-resolved by default. glibc will perform name resolution using &#x27;nss-resolve&#x27; rather than &#x27;nss-dns&#x27;.</p></blockquote><blockquote><p>systemd-resolved has been enabled by default in Ubuntu since Ubuntu 16.10, but please note we are doing this differently than Ubuntu has. Ubuntu does not use nss-resolve. Instead, Ubuntu uses the traditional nss-dns provided by glibc upstream, so glibc on Ubuntu continues to read /etc/resolv.conf, as is traditional. This extra step is not useful and not recommended by upstream. We want to follow upstream recommendations in using nss-resolve instead.</p></blockquote><h2 id="服务和命令行工具"><a href="#服务和命令行工具" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>服务和命令行工具</h2><p>查看服务状态:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ systemctl status systemd-resolved </span><span class="code-line">● systemd-resolved.service - Network Name Resolution </span><span class="code-line"> Loaded: loaded <span class="token punctuation">(</span>/usr/lib/systemd/system/systemd-resolved.service<span class="token punctuation">;</span> enabled<span class="token punctuation">;</span> vendor preset: enabled<span class="token punctuation">)</span> </span><span class="code-line"> Active: active <span class="token punctuation">(</span>running<span class="token punctuation">)</span> since Sun <span class="token number">2020</span>-12-20 <span class="token number">10</span>:08:05 CST<span class="token punctuation">;</span> 11h ago </span><span class="code-line"> Docs: man:systemd-resolved.service<span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">)</span> </span><span class="code-line"> https://www.freedesktop.org/wiki/Software/systemd/resolved </span><span class="code-line"> https://www.freedesktop.org/wiki/Software/systemd/writing-network-configuration-managers </span><span class="code-line"> https://www.freedesktop.org/wiki/Software/systemd/writing-resolver-clients </span><span class="code-line"> Main PID: <span class="token number">2695</span> <span class="token punctuation">(</span>systemd-resolve<span class="token punctuation">)</span> </span><span class="code-line"> Status: <span class="token string">&quot;Processing requests...&quot;</span> </span><span class="code-line"> Tasks: <span class="token number">1</span> <span class="token punctuation">(</span>limit: <span class="token number">38311</span><span class="token punctuation">)</span> </span><span class="code-line"> Memory: <span class="token number">13</span>.0M </span><span class="code-line"> CPU: <span class="token number">8</span>.384s </span><span class="code-line"> CGroup: /system.slice/systemd-resolved.service </span><span class="code-line"> └─2695 /usr/lib/systemd/systemd-resolved </span></code></pre></div><p>查看当前状态:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ resolvectl status </span><span class="code-line">Global </span><span class="code-line"> Protocols: <span class="token variable assign-left">LLMNR</span><span class="token operator">=</span>resolve <span class="token variable parameter">-mDNS</span> <span class="token variable parameter">-DNSOverTLS</span> <span class="token variable assign-left">DNSSEC</span><span class="token operator">=</span>no/unsupported </span><span class="code-line"> resolv.conf mode: stub </span><span class="code-line">Current DNS Server: <span class="token number">127.0</span>.0.1:5354 </span><span class="code-line"> DNS Servers: <span class="token number">127.0</span>.0.1:5354 </span></code></pre></div><p>DNS解析(老灯这里特意查询了两次,主要是通过二者的消耗时间对比cache的效果):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ resolvectl query <span class="token number">163</span>.com </span><span class="code-line"><span class="token number">163</span>.com: <span class="token number">123.58</span>.180.7 </span><span class="code-line"> <span class="token number">123.58</span>.180.8 </span><span class="code-line"> </span><span class="code-line">-- Information acquired via protocol DNS <span class="token keyword">in</span> <span class="token number">7</span>.7ms. </span><span class="code-line">-- Data is authenticated: no </span><span class="code-line">❯ resolvectl query <span class="token number">163</span>.com </span><span class="code-line"><span class="token number">163</span>.com: <span class="token number">123.58</span>.180.7 </span><span class="code-line"> <span class="token number">123.58</span>.180.8 </span><span class="code-line"> </span><span class="code-line">-- Information acquired via protocol DNS <span class="token keyword">in</span> 624us. </span><span class="code-line">-- Data is authenticated: no </span><span class="code-line"> </span></code></pre></div><p><code>resolvectl statistics</code> 可查询统计信息,比如缓存命中率,缓存条目数量等</p><p><code>resolvectl flush-caches</code> 可清除查询缓存</p><p>其它参数可通过<code>resolvectl -h</code> 查看.</p><h2 id="特别注意"><a href="#特别注意" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>特别注意</h2><blockquote><p><code>systemd-resolved</code> 不能当作局域网DNS cache服务器使用,它只能用于本机,因为它监听的是<code>lo</code> (loopback网卡)</p></blockquote><p>stackoverflow上已经有大佬回复了,甚至把相关的代码都贴出来了. <a href="https://unix.stackexchange.com/a/549315/405754">https://unix.stackexchange.com/a/549315/405754</a></p><blockquote><p>You can&#x27;t. As cristian-rodríguez mentioned above, it was strictly designed to provide services to loopback only. Not even an alternative solution using <code>net.ipv4.conf.all.route_localnet=1</code> + iptables NAT (such as <a href="https://serverfault.com/questions/211536/iptables-port-redirect-not-working-for-localhost">https://serverfault.com/questions/211536/iptables-port-redirect-not-working-for-localhost</a>), <a href="https://superuser.com/questions/594163/how-do-i-route-a-port-range-in-a-linux-host-to-a-guest-vm">https://superuser.com/questions/594163/how-do-i-route-a-port-range-in-a-linux-host-to-a-guest-vm</a>), and <a href="https://stackoverflow.com/questions/18580637/iptables-redirect-from-external-interface-to-loopbacks-port">https://stackoverflow.com/questions/18580637/iptables-redirect-from-external-interface-to-loopbacks-port</a>) will work, since systemd-resolve explicitly inspects if the destination is outside the loopback network. See the code below for static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p)</p></blockquote><div class="relative"><pre><code class="code-highlight language-c"><span class="code-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">in_addr_is_localhost</span><span class="token punctuation">(</span>p<span class="token operator">-&gt;</span>family<span class="token punctuation">,</span> <span class="token operator">&amp;</span>p<span class="token operator">-&gt;</span>sender<span class="token punctuation">)</span> <span class="token operator">&lt;=</span> <span class="token number">0</span> <span class="token operator">||</span> </span><span class="code-line"> <span class="token function">in_addr_is_localhost</span><span class="token punctuation">(</span>p<span class="token operator">-&gt;</span>family<span class="token punctuation">,</span> <span class="token operator">&amp;</span>p<span class="token operator">-&gt;</span>destination<span class="token punctuation">)</span> <span class="token operator">&lt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">log_error</span><span class="token punctuation">(</span><span class="token string">&quot;Got packet on unexpected IP range, refusing.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">dns_stub_send_failure</span><span class="token punctuation">(</span>m<span class="token punctuation">,</span> s<span class="token punctuation">,</span> p<span class="token punctuation">,</span> DNS_RCODE_SERVFAIL<span class="token punctuation">,</span> false<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">goto</span> fail<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://fedoramagazine.org/systemd-resolved-introduction-to-split-dns/">https://fedoramagazine.org/systemd-resolved-introduction-to-split-dns/</a> <a href="https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html">https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html</a> <a href="https://fedoraproject.org/wiki/Changes/systemd-resolved">https://fedoraproject.org/wiki/Changes/systemd-resolved</a></p> Sun, 20 Dec 2020 13:20:59 GMT ttyS3 Fedora https://ttys3.dev/blog/fedora32-upgrade-to-fedora33 Fedora 32 升级到 Fedora 33 https://ttys3.dev/blog/fedora32-upgrade-to-fedora33 <p>Fedora 33 在 10月27号准时发布。</p><p>官方公告见这儿: <a href="https://fedoramagazine.org/announcing-fedora-33/">https://fedoramagazine.org/announcing-fedora-33/</a></p><p>从官方公告的HTML meta <code>article:published_time</code> 可看到, 文章发布时间为 <code>2020-10-27T14:00:14+00:00</code>, 也就是 CST 2020-10-27 22:00 左右。 老灯现在写文章的时候为 <code>Thu Oct 29 01:03:39 AM CST 2020</code>, 因此距离 Fedora 33正式发布已经整整一天多时间了。</p><h2 id="如何从f32升级到f33"><a href="#如何从f32升级到f33" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何从F32升级到F33</h2><p>步骤基本上是一样的,参考我之前的文章 《<a href="/post/linux/fedora/fedora31-upgrade-to-fedora32/">Fedora 31 升级到 Fedora 32</a>》</p><h3 id="选择合适的镜像站"><a href="#选择合适的镜像站" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>选择合适的镜像站</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">date</span> </span><span class="code-line">Wed <span class="token number">28</span> Oct <span class="token number">2020</span> <span class="token number">10</span>:17:21 PM CST </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">--- mirrors.ustc.edu.cn <span class="token function">ping</span> statistics --- </span><span class="code-line"><span class="token number">100</span> packets transmitted, <span class="token number">100</span> received, <span class="token number">0</span>% packet loss, <span class="token function">time</span> 99112ms </span><span class="code-line">rtt min/avg/max/mdev <span class="token operator">=</span> <span class="token number">33.822</span>/46.199/287.057/43.688 ms </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">--- cdnmirrors.s.tuna.tsinghua.edu.cn <span class="token function">ping</span> statistics --- </span><span class="code-line"><span class="token number">100</span> packets transmitted, <span class="token number">86</span> received, <span class="token number">14</span>% packet loss, <span class="token function">time</span> 100655ms </span><span class="code-line">rtt min/avg/max/mdev <span class="token operator">=</span> <span class="token number">54.097</span>/65.754/270.979/35.645 ms </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">--- opentuna.cn <span class="token function">ping</span> statistics --- </span><span class="code-line"><span class="token number">100</span> packets transmitted, <span class="token number">100</span> received, <span class="token number">0</span>% packet loss, <span class="token function">time</span> 99131ms </span><span class="code-line">rtt min/avg/max/mdev <span class="token operator">=</span> <span class="token number">7.345</span>/17.239/266.296/38.896 ms </span></code></pre></div><p>如果是看ping的结果的话, 看上去 <code>opentuna.cn</code> 是最佳选项。 但是 <code>opentuna</code> 没有 <code>rpmfusion</code> 源, 作为一个 Fedora 用户<code>rpmfusion</code> 源几乎是必须的。 因此,老灯这里直接pass掉<code>opentuna</code> 源。</p><p>其它源,同步不够及时或有其它问题,暂时还没法用于 Fedora 33:</p><p>比如上海交大的, 还没同步 F33 源。<code>https://mirrors.sjtug.sjtu.edu.cn/fedora/linux/releases/33/</code> 直接404 ustc 的同步是有问题(或者不及时)的, <code>https://mirrors.ustc.edu.cn/fedora/releases/33/Modular/x86_64/os/repodata/</code> 下面完全是空的。</p><p>最好老灯测试,只有 tuna 的源(<code>https://mirrors.tuna.tsinghua.edu.cn/fedora</code>)是同步OK的。</p><p>老灯把所有源(Fedora 和 rpmfusion)都换成 tuna 的 (因为截止到当前时间, ustc和sjtug的源还没法用于F33):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">cd</span> /etc/yum.repos.d </span><span class="code-line"><span class="token function">sed</span> <span class="token variable parameter">-i</span> <span class="token string">&#x27;s|mirrors.ustc.edu.cn|mirrors.tuna.tsinghua.edu.cn|g&#x27;</span> <span class="token variable"><span class="token variable">`</span>rg <span class="token variable parameter">-l</span> mirrors.ustc.edu.cn<span class="token variable">`</span></span> </span></code></pre></div><h3 id="升级系统到f33"><a href="#升级系统到f33" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>升级系统到F33</h3><p>升级过程还是非常顺利的,基本上参数官方文档: <a href="https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/">https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/</a></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 首先确保系统更新到F31当前最新版</span> </span><span class="code-line"><span class="token function">sudo</span> dnf upgrade <span class="token variable parameter">--refresh</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 安装dnf system-upgrade 插件(如果没有安装过的话)</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> dnf-plugin-system-upgrade </span><span class="code-line"><span class="token comment"># 下载升级文件, 注意这里的--releasever=32, 下次如果要升级到33, 只需要改动这里 --releasever=33 即可</span> </span><span class="code-line"><span class="token function">sudo</span> dnf system-upgrade download <span class="token variable parameter">--refresh</span> <span class="token variable parameter">--releasever</span><span class="token operator">=</span><span class="token number">32</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 确认前面的操作都进行OK了,就可以执行以下命令开始升级</span> </span><span class="code-line"><span class="token function">sudo</span> dnf system-upgrade <span class="token function">reboot</span> </span></code></pre></div><p>我在升级过程中还是遇到点小问题的,不过有惊无险:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">/etc/yum.repos.d root@8700k 3m 40s </span><span class="code-line">❯ dnf system-upgrade download <span class="token variable parameter">--refresh</span> <span class="token variable parameter">--releasever</span><span class="token operator">=</span><span class="token number">33</span> </span><span class="code-line">Ignoring repositories: copr:copr.fedorainfracloud.org:prince781:vala-language-server, scootersoftware </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;lsvpd&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;xorg-x11-drv-armsoc&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;k3b-extras-freeworld&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;powerpc-utils&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;gstreamer1-plugins-bad-nonfree&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;cvsgraph&quot;</span> </span><span class="code-line"><span class="token punctuation">..</span>. </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;fedora-user-agent-chrome&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;google-croscore-cousine-fonts&quot;</span> </span><span class="code-line">Error: </span><span class="code-line"> Problem: package gstreamer1-plugins-ugly-free-devel-1.16.2-2.fc32.x86_64 requires gstreamer1-plugins-ugly-free <span class="token operator">=</span> <span class="token number">1.16</span>.2-2.fc32, but none of the providers can be installed </span><span class="code-line"> - gstreamer1-plugins-ugly-free-1.16.2-2.fc32.x86_64 does not belong to a distupgrade repository </span><span class="code-line"> - problem with installed package gstreamer1-plugins-ugly-free-devel-1.16.2-2.fc32.x86_64 </span><span class="code-line"><span class="token punctuation">(</span>try to <span class="token function">add</span> <span class="token string">&#x27;--skip-broken&#x27;</span> to skip uninstallable packages<span class="token punctuation">)</span> </span><span class="code-line"> </span></code></pre></div><p>前面的 No match 其实可以通过<code>--skip-broken</code>参数解决,但是这个Error是要人工介入处理的。 错误信息已经提示我们了,因此直接移除掉<code>gstreamer1-plugins-ugly-free-devel</code>就好了:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">dnf remove gstreamer1-plugins-ugly-free-devel </span></code></pre></div><p>然后继续接着下载:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">dnf system-upgrade download <span class="token variable parameter">--refresh</span> <span class="token variable parameter">--releasever</span><span class="token operator">=</span><span class="token number">33</span> --skip-broken </span></code></pre></div><p>输出大概如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">/etc/yum.repos.d root@8700k </span><span class="code-line">❯ dnf system-upgrade download <span class="token variable parameter">--refresh</span> <span class="token variable parameter">--releasever</span><span class="token operator">=</span><span class="token number">33</span> --skip-broken </span><span class="code-line">Before you <span class="token builtin class-name">continue</span> ensure that your system is fully upgraded by running <span class="token string">&quot;dnf --refresh upgrade&quot;</span><span class="token builtin class-name">.</span> Do you want to <span class="token builtin class-name">continue</span> <span class="token punctuation">[</span>y/N<span class="token punctuation">]</span>: y </span><span class="code-line"><span class="token punctuation">..</span>. </span><span class="code-line">Ignoring repositories: copr:copr.fedorainfracloud.org:prince781:vala-language-server </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;lsvpd&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;k3b-extras-freeworld&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;xorg-x11-drv-armsoc&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;powerpc-utils&quot;</span> </span><span class="code-line"><span class="token punctuation">..</span>. </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;tharlon-fonts&quot;</span> </span><span class="code-line">No match <span class="token keyword">for</span> group package <span class="token string">&quot;oflb-icelandic-fonts&quot;</span> </span><span class="code-line">Dependencies resolved. </span><span class="code-line"><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span> </span><span class="code-line"> Package Architecture Version Repository Size </span><span class="code-line"><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span> </span><span class="code-line">Installing: </span><span class="code-line"> kernel x86_64 <span class="token number">5.8</span>.16-300.fc33 updates <span class="token number">6.9</span> k </span><span class="code-line"> kernel-core x86_64 <span class="token number">5.8</span>.16-300.fc33 updates <span class="token number">33</span> M </span><span class="code-line"> kernel-devel x86_64 <span class="token number">5.8</span>.16-300.fc33 updates <span class="token number">13</span> M </span><span class="code-line"> kernel-modules x86_64 <span class="token number">5.8</span>.16-300.fc33 updates <span class="token number">30</span> M </span><span class="code-line"> kernel-modules-extra x86_64 <span class="token number">5.8</span>.16-300.fc33 updates <span class="token number">2.0</span> M </span><span class="code-line">Upgrading: </span><span class="code-line"> GConf2 x86_64 <span class="token number">3.2</span>.6-29.fc33 fedora <span class="token number">1.0</span> M </span><span class="code-line"> GeoIP x86_64 <span class="token number">1.6</span>.12-8.fc33 fedora <span class="token number">121</span> k </span><span class="code-line"> GeoIP-GeoLite-data noarch <span class="token number">2018.06</span>-6.fc33 fedora <span class="token number">681</span> k </span><span class="code-line"> GeoIP-devel x86_64 <span class="token number">1.6</span>.12-8.fc33 fedora <span class="token number">12</span> k </span><span class="code-line"> GraphicsMagick x86_64 <span class="token number">1.3</span>.35-3.fc33 fedora <span class="token number">1.5</span> M </span><span class="code-line"> GraphicsMagick-devel x86_64 <span class="token number">1.3</span>.35-3.fc33 fedora <span class="token number">71</span> k </span><span class="code-line"> <span class="token punctuation">..</span>. </span><span class="code-line"> python3-libdnf x86_64 <span class="token number">0.54</span>.2-2.fc33 updates <span class="token number">775</span> k </span><span class="code-line"> qbittorrent x86_64 <span class="token number">1</span>:4.2.5-4.fc33 fedora <span class="token number">5.7</span> M </span><span class="code-line"> yum noarch <span class="token number">4.4</span>.0-2.fc33 updates <span class="token number">43</span> k </span><span class="code-line">Upgrading Groups: </span><span class="code-line"> Anaconda tools </span><span class="code-line"> base-x </span><span class="code-line"> C Development Tools and Libraries </span><span class="code-line"> Container Management </span><span class="code-line"> Development Tools </span><span class="code-line"> Firefox Web Browser </span><span class="code-line"> Guest Desktop Agents </span><span class="code-line"> LibreOffice </span><span class="code-line"> Common NetworkManager Submodules </span><span class="code-line"> Printing Support </span><span class="code-line"> Fedora Workstation product core </span><span class="code-line"> x86 Baremetal Tools </span><span class="code-line"> GNOME Desktop Environment </span><span class="code-line"> Multimedia </span><span class="code-line"> Core </span><span class="code-line"> Fonts </span><span class="code-line"> Hardware Support </span><span class="code-line"> Sound and Video </span><span class="code-line"> </span><span class="code-line">Transaction Summary </span><span class="code-line"><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span> </span><span class="code-line">Install <span class="token number">187</span> Packages </span><span class="code-line">Upgrade <span class="token number">2537</span> Packages </span><span class="code-line">Remove <span class="token number">8</span> Packages </span><span class="code-line">Downgrade <span class="token number">24</span> Packages </span><span class="code-line"> </span><span class="code-line">Total download size: <span class="token number">3.0</span> G </span><span class="code-line">DNF will only download packages, <span class="token function">install</span> gpg keys, and check the transaction. </span><span class="code-line">Is this ok <span class="token punctuation">[</span>y/N<span class="token punctuation">]</span>: </span></code></pre></div><p>y 回车后就开始下载. 大概下载了 3GB 的文件:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token punctuation">(</span><span class="token number">2748</span>/2748<span class="token punctuation">)</span>: xorg-x11-drv-nvidia-libs-455.28-1.fc33.x86_64.rpm <span class="token number">6.2</span> MB/s <span class="token operator">|</span> <span class="token number">78</span> MB 00:12 </span><span class="code-line">---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- </span><span class="code-line">Total <span class="token number">3.3</span> MB/s <span class="token operator">|</span> <span class="token number">3.0</span> GB <span class="token number">15</span>:18 </span><span class="code-line">warning: /var/lib/dnf/system-upgrade/updates-236f50538cae036d/packages/cpp-10.2.1-5.fc33.x86_64.rpm: Header V4 RSA/SHA256 Signature, key ID 9570ff31: NOKEY </span><span class="code-line">Fedora <span class="token number">33</span> - x86_64 - Updates <span class="token number">1.6</span> MB/s <span class="token operator">|</span> <span class="token number">1.6</span> kB 00:00 </span><span class="code-line">Importing GPG key 0x9570FF31: </span><span class="code-line"> Userid <span class="token builtin class-name">:</span> <span class="token string">&quot;Fedora (33) &lt;[email protected]&gt;&quot;</span> </span><span class="code-line"> Fingerprint: 963A 2BEB 0200 <span class="token number">9608</span> FE67 EA42 49FD <span class="token number">7749</span> <span class="token number">9570</span> FF31 </span><span class="code-line"> From <span class="token builtin class-name">:</span> /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-33-x86_64 </span><span class="code-line">Is this ok <span class="token punctuation">[</span>y/N<span class="token punctuation">]</span>: y </span><span class="code-line">Key imported successfully </span><span class="code-line">warning: /var/lib/dnf/system-upgrade/rpmfusion-free-83022c35002eaaf4/packages/svt-hevc-libs-1.5.0-2.fc33.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID d651ff2e: NOKEY </span><span class="code-line">RPM Fusion <span class="token keyword">for</span> Fedora <span class="token number">33</span> - Free <span class="token number">1.6</span> MB/s <span class="token operator">|</span> <span class="token number">1.7</span> kB 00:00 </span><span class="code-line">Importing GPG key 0xD651FF2E: </span><span class="code-line"> Userid <span class="token builtin class-name">:</span> <span class="token string">&quot;RPM Fusion free repository for Fedora (2020) &lt;[email protected]&gt;&quot;</span> </span><span class="code-line"> Fingerprint: E9A4 91A3 DE24 <span class="token number">7814</span> E7E0 67EA E06F 8ECD D651 FF2E </span><span class="code-line"> From <span class="token builtin class-name">:</span> /etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-free-fedora-33 </span><span class="code-line">Is this ok <span class="token punctuation">[</span>y/N<span class="token punctuation">]</span>: y </span><span class="code-line">Key imported successfully </span><span class="code-line">warning: /var/lib/dnf/system-upgrade/rpmfusion-nonfree-09983ab4040af696/packages/akmod-nvidia-455.28-1.fc33.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID 94843c65: NOKEY </span><span class="code-line">RPM Fusion <span class="token keyword">for</span> Fedora <span class="token number">33</span> - Nonfree <span class="token number">1.6</span> MB/s <span class="token operator">|</span> <span class="token number">1.7</span> kB 00:00 </span><span class="code-line">Importing GPG key 0x94843C65: </span><span class="code-line"> Userid <span class="token builtin class-name">:</span> <span class="token string">&quot;RPM Fusion nonfree repository for Fedora (2020) &lt;[email protected]&gt;&quot;</span> </span><span class="code-line"> Fingerprint: 79BD B88F 9BBF <span class="token number">7391</span> 0FD4 095B 6A2A F961 <span class="token number">9484</span> 3C65 </span><span class="code-line"> From <span class="token builtin class-name">:</span> /etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-nonfree-fedora-33 </span><span class="code-line">Is this ok <span class="token punctuation">[</span>y/N<span class="token punctuation">]</span>: y </span><span class="code-line">Key imported successfully </span><span class="code-line">Running transaction check </span><span class="code-line">Transaction check succeeded. </span><span class="code-line">Running transaction <span class="token builtin class-name">test</span> </span><span class="code-line">Transaction <span class="token builtin class-name">test</span> succeeded. </span><span class="code-line">Complete<span class="token operator">!</span> </span><span class="code-line">Download complete<span class="token operator">!</span> Use <span class="token string">&#x27;dnf system-upgrade reboot&#x27;</span> to start the upgrade. </span><span class="code-line">To remove cached metadata and transaction use <span class="token string">&#x27;dnf system-upgrade clean&#x27;</span> </span><span class="code-line">The downloaded packages were saved <span class="token keyword">in</span> cache <span class="token keyword">until</span> the next successful transaction. </span><span class="code-line">You can remove cached packages by executing <span class="token string">&#x27;dnf clean packages&#x27;</span><span class="token builtin class-name">.</span> </span></code></pre></div><p>执行 <code>dnf system-upgrade reboot</code> 后,系统卡了1分钟左右(黑屏状态)才显示console, 然后成功重启。</p><p>重启成功后,GRUB 菜单还是 F32 的选项的,因为更新还没安装嘛。进入之后,整个屏是黑的,有个光标在闪,怀疑是N卡显卡驱动问题。 不过实际上是在进行升级安装过程的,我怎么知道的?我是后面才知道的。 黑屏了,我并没有马上强制按电源键关机再启动。而是出去抽了根烟,然后等了个几分钟再回来看。发现还是黑屏。 于是我按电源键强制关机了,再启动的时候,发现熟悉的 Fedora 33 Grub启动项。</p><blockquote><p>本次升级, 没有翻车。</p></blockquote><p>但是有点后怕,这种情况黑屏的时候,还应该等待久一些(比如给它20分钟或30分钟的时间)再关机会更保险,毕竟看不到console不好判断系统升级是否正常结束。</p><p>安装完之后,需要进入 <code>https://extensions.gnome.org/local/</code> 升级一下 GNOME 扩展。 升级完GNOME扩展有些会默认显示ERROR不工作, 要退出登录再登录一下。</p><h3 id="f33-的改变"><a href="#f33-的改变" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>F33 的改变</h3><p>不得不说, Fedora 每次发版本都会带来新鲜玩意, 改动大刀阔斧,有时甚至能带来惊喜。</p><p>内核版本基本上和 F32 一样:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">Linux 8700k.localhost <span class="token number">5.8</span>.16-200.fc32.x86_64 <span class="token comment">#1 SMP Mon Oct 19 14:17:16 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux</span> </span><span class="code-line">Linux 8700k.localhost <span class="token number">5.8</span>.16-300.fc33.x86_64 <span class="token comment">#1 SMP Mon Oct 19 13:18:33 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux</span> </span></code></pre></div><p>官方默认是 GNOME3, 其它 DE 的可从 spins <a href="https://spins.fedoraproject.org/en/">https://spins.fedoraproject.org/en/</a> 下载到。</p><p>GNOME 升级到 3.38 <a href="https://www.gnome.org/news/2020/09/gnome-3-38-released/">https://www.gnome.org/news/2020/09/gnome-3-38-released/</a></p><p>btrfs 作为默认的文件系统 <a href="https://fedoramagazine.org/btrfs-coming-to-fedora-33/">https://fedoramagazine.org/btrfs-coming-to-fedora-33/</a></p><p>Network Time Security (NTS) 支持, 但是要注意: The default NTP client in Fedora is chrony. Chrony added NTS support in version 4.0. The default configuration hasn’t changed. Chrony still uses public servers from the pool.ntp.org project and NTS is not enabled by default.</p><p>参考 <a href="https://fedoramagazine.org/secure-ntp-with-nts/">https://fedoramagazine.org/secure-ntp-with-nts/</a></p><p>除了 x86_64 架构的,alternate architectures: ARM AArch64, Power, and S390x 也可在 <a href="https://alt.fedoraproject.org/alt/">https://alt.fedoraproject.org/alt/</a> 下载到。 改进了对 Pine64,NVidia Jetson 64, Rockchip SoC(如Rock960, RockPro64, and Rock64等)的支持。</p><p>提供专门的 IoT 版本下载, 采用<a href="https://ostreedev.github.io/ostree/">OSTree</a>技术, 目前支持的架构有 <code>aarch64</code>, <code>armhfp</code> 和 <code>x86_64</code></p><p>系统底层库升级,如 Binutils 2.34, GNU C Library 2.32, Update the system JDK in Fedora from java-1.8.0-openjdk to java-11-openjdk, LLVM 11, GNU make 4.3,RPM 4.16, Sqlite RpmDB(Change format of the RPM database from Berkeley DB to a new Sqlite format.), swap on zram, systemd-resolved, Enable systemd-resolved by default. glibc will perform name resolution using nss-resolve rather than nss-dns.</p><p>编程语言库升级,包括 Python 3.9, Node.js 14.x, Ruby on Rails 6.0, and Perl 5.32, Golang 1.15 等</p><p>EarlyOOM 服务 (<code>earlyoom.service</code>) 默认开启可改善内存不足时的用户体验。</p><p>nano 被设置成了 系统默认的编辑器, 这一点老灯承认, 明智之举。因为会Vim的人会自己配置 EDITOR=vim, 不会Vim的人才会用默认的 nano.</p><p>完整的列表请见官方文档: <a href="https://fedoraproject.org/wiki/Releases/33/ChangeSet">https://fedoraproject.org/wiki/Releases/33/ChangeSet</a></p><h2 id="其它参考资料"><a href="#其它参考资料" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它参考资料</h2><p><a href="https://fedoraproject.org/wiki/Releases/33/ChangeSet">https://fedoraproject.org/wiki/Releases/33/ChangeSet</a></p><p><a href="https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/">https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/</a></p><p><a href="https://www.fosslinux.com/43968/fedora-33-whats-new-and-how-to-upgrade.htm">https://www.fosslinux.com/43968/fedora-33-whats-new-and-how-to-upgrade.htm</a></p><p><a href="https://www.cyberciti.biz/faq/upgrade-fedora-31-to-fedora-32-using-the-cli/">https://www.cyberciti.biz/faq/upgrade-fedora-31-to-fedora-32-using-the-cli/</a></p><p><a href="https://fedorapeople.org/groups/schedule/f-33/f-33-key-tasks.html">https://fedorapeople.org/groups/schedule/f-33/f-33-key-tasks.html</a></p> Wed, 28 Oct 2020 16:36:44 GMT ttyS3 fedoraupgrade https://ttys3.dev/blog/git-batch-change-commit-author-and-email 如何批量修改 Git 提交记录中的作者名称和邮箱 https://ttys3.dev/blog/git-batch-change-commit-author-and-email <p>适用场景:</p><blockquote><p>已经提交了N个commit才发现用的配置(<code>user.name</code> 和 <code>user.email</code>)错了,比如要用个人邮箱的,用成了公司邮箱。 基于隐私考虑,我们需要把公司邮箱和昵称替换掉。</p></blockquote><p>主要是用到<a href="https://github.com/newren/git-filter-repo">git-filter-repo</a>的<strong>CALLBACKS</strong>功能</p><p>参考文档 <a href="https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#CALLBACKS">https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#CALLBACKS</a></p><p>方法很简单:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment">#将所有用户名中包含的foo替换成ttys3 (注意,不支持中文)</span> </span><span class="code-line"><span class="token function">git</span> filter-repo --name-callback <span class="token string">&#x27;return name.replace(b&quot;foo&quot;, b&quot;ttys3&quot;)&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#将所有commit信息的email中包含的 [email protected] 替换成 [email protected]</span> </span><span class="code-line"><span class="token function">git</span> filter-repo --email-callback <span class="token string">&#x27;return email.replace(b&quot;[email protected]&quot;, b&quot;[email protected]&quot;)&#x27;</span> </span></code></pre></div><p>如果是中文,则不能用 bytes, 要用 string 然后再 encode, 如:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment">#将所有用户名中包含的 &quot;旧名称&quot; 替换成 &quot;新名称&quot;</span> </span><span class="code-line"><span class="token function">git</span> filter-repo --name-callback <span class="token string">&#x27;return name.replace(&quot;旧名称&quot;.encode(), &quot;新名称&quot;.encode())&#x27;</span> </span></code></pre></div><p>你不能直接对 CJK 字符使用 <code>b&quot;xxxxxxx&quot;</code> , 不然你会收到 git-filter-repo 提示 &quot;SyntaxError: bytes can only contain ASCII literal characters&quot; 的 python 语法错误</p><p>注意:</p><blockquote><ol><li>替换是部分匹配的,因此注意使用尽可能长的子串</li><li>操作会重写所有被匹配到的commit, 因此,如果repo已经push到了远程仓库时,操作要慎重</li></ol></blockquote><h2 id="refs"><a href="#refs" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>refs</h2><p><a href="https://github.com/newren/git-filter-repo/issues/383#issuecomment-1189511149">https://github.com/newren/git-filter-repo/issues/383#issuecomment-1189511149</a></p> Sun, 06 Sep 2020 18:07:42 GMT ttyS3 Git https://ttys3.dev/blog/neovim-gui Neovim GUI 简单尝试 https://ttys3.dev/blog/neovim-gui <p><a href="https://neovim.io/">Neovim</a> 这个项目大概开始于2014年,主要目的是打造现代化的Vim. 不考虑vi和旧版本系统的兼容性。不同于Vim,官方有基于GTK的gvim, Neovim 只有 <a href="https://github.com/neovim/neovim/wiki/Related-projects#gui">第三方的GUI</a>.</p><p>老灯肯定是会先Golang或Rust版的。</p><p><a href="https://github.com/Kethku/neovide">https://github.com/Kethku/neovide</a> 有1.5K star, clone 下来编译一把。然后发现报错了。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"> Compiling skia-bindings v0.27.3 </span><span class="code-line"> Compiling rust-embed v5.5.1 </span><span class="code-line"> Compiling thiserror v1.0.19 </span><span class="code-line"> Compiling <span class="token function">which</span> v4.0.0 </span><span class="code-line"> Compiling tokio v0.2.20 </span><span class="code-line"> Compiling futures-util v0.3.4 </span><span class="code-line"> Compiling futures-executor v0.3.4 </span><span class="code-line"> Compiling futures v0.3.4 </span><span class="code-line"> Compiling pin-project v0.4.13 </span><span class="code-line"> Compiling nvim-rs v0.1.1-alpha.0 <span class="token punctuation">(</span>https://github.com/ttys3/nvim-rs<span class="token comment">#acfcd741)</span> </span><span class="code-line"> Compiling skia-safe v0.27.3 </span><span class="code-line"> Compiling skulpin-renderer v0.3.1 <span class="token punctuation">(</span>https://github.com/aclysma/skulpin<span class="token comment">#6139a1f1)</span> </span><span class="code-line"> Compiling skulpin-renderer-winit v0.3.1 <span class="token punctuation">(</span>https://github.com/aclysma/skulpin<span class="token comment">#6139a1f1)</span> </span><span class="code-line"> Compiling skulpin-renderer-sdl2 v0.3.3 <span class="token punctuation">(</span>https://github.com/aclysma/skulpin<span class="token comment">#6139a1f1)</span> </span><span class="code-line"> Compiling skulpin-app-winit v0.3.0 <span class="token punctuation">(</span>https://github.com/aclysma/skulpin<span class="token comment">#6139a1f1)</span> </span><span class="code-line"> Compiling skulpin v0.9.4 <span class="token punctuation">(</span>https://github.com/aclysma/skulpin<span class="token comment">#6139a1f1)</span> </span><span class="code-line">error: linking with <span class="token variable"><span class="token variable">`</span>cc<span class="token variable">`</span></span> failed: <span class="token builtin class-name">exit</span> code: <span class="token number">1</span> </span><span class="code-line"> <span class="token operator">|</span> </span><span class="code-line"> <span class="token operator">=</span> note: <span class="token string">&quot;cc&quot;</span> <span class="token string">&quot;-Wl,--as-needed&quot;</span> <span class="token string">&quot;-Wl,-z,noexecstack&quot;</span> <span class="token string">&quot;-m64&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/home/ttys3/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib&quot;</span> <span class="token string">&quot;/home/ttys3/repo/rust/neovide/target/release/deps/neovide-859e1fbe14249d62.which-4752fad7c46da7e1.which.dx3vn4zm-cgu.0.rcgu.o.rcgu.o&quot;</span> <span class="token string">&quot;-o&quot;</span> <span class="token string">&quot;/home/ttys3/repo/rust/neovide/target/release/deps/neovide-859e1fbe14249d62&quot;</span> <span class="token string">&quot;-Wl,--gc-sections&quot;</span> <span class="token string">&quot;-pie&quot;</span> <span class="token string">&quot;-Wl,-zrelro&quot;</span> <span class="token string">&quot;-Wl,-znow&quot;</span> <span class="token string">&quot;-Wl,-O1&quot;</span> <span class="token string">&quot;-nodefaultlibs&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/home/ttys3/repo/rust/neovide/target/release/deps&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/usr/lib64&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/usr/lib64&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/usr/lib64&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/usr/lib64&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/home/ttys3/repo/rust/neovide/target/release/build/libloading-e62ea45709dbd618/out&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/home/ttys3/repo/rust/neovide/target/release/build/skia-bindings-2d1116dc7243ba64/out/skia&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/home/ttys3/repo/rust/neovide/target/release/build/sdl2-sys-1bc6cf995ffc0881/out/lib&quot;</span> <span class="token string">&quot;-L&quot;</span> <span class="token string">&quot;/home/ttys3/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib&quot;</span> <span class="token string">&quot;-Wl,-Bstatic&quot;</span> <span class="token string">&quot;/tmp/rustcSwsrGo/libsdl2_sys-ab14be8f9d7d1911.rlib&quot;</span> <span class="token string">&quot;/tmp/rustcSwsrGo/libskia_bindings-1cb3591282aafaf7.rlib&quot;</span> <span class="token string">&quot;/tmp/rustcSwsrGo/liblibloading-533412b9dac9bc03.rlib&quot;</span> <span class="token string">&quot;-Wl,--start-group&quot;</span> <span class="token string">&quot;/tmp/rustcSwsrGo/libbacktrace_sys-23bdd98b0574083e.rlib&quot;</span> <span class="token string">&quot;-Wl,--end-group&quot;</span> <span class="token string">&quot;/home/ttys3/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-5a0398ee67f74664.rlib&quot;</span> <span class="token string">&quot;-Wl,-Bdynamic&quot;</span> <span class="token string">&quot;-lharfbuzz&quot;</span> <span class="token string">&quot;-lfontconfig&quot;</span> <span class="token string">&quot;-lfreetype&quot;</span> <span class="token string">&quot;-lexpat&quot;</span> <span class="token string">&quot;-lfreetype&quot;</span> <span class="token string">&quot;-ldl&quot;</span> <span class="token string">&quot;-lstdc++&quot;</span> <span class="token string">&quot;-lfontconfig&quot;</span> <span class="token string">&quot;-lfreetype&quot;</span> <span class="token string">&quot;-ldl&quot;</span> <span class="token string">&quot;-lutil&quot;</span> <span class="token string">&quot;-ldl&quot;</span> <span class="token string">&quot;-lutil&quot;</span> <span class="token string">&quot;-ldl&quot;</span> <span class="token string">&quot;-lrt&quot;</span> <span class="token string">&quot;-lpthread&quot;</span> <span class="token string">&quot;-lgcc_s&quot;</span> <span class="token string">&quot;-lc&quot;</span> <span class="token string">&quot;-lm&quot;</span> <span class="token string">&quot;-lrt&quot;</span> <span class="token string">&quot;-lpthread&quot;</span> <span class="token string">&quot;-lutil&quot;</span> <span class="token string">&quot;-ldl&quot;</span> <span class="token string">&quot;-lutil&quot;</span> </span><span class="code-line"> <span class="token operator">=</span> note: /usr/bin/ld: /tmp/rustcSwsrGo/libsdl2_sys-ab14be8f9d7d1911.rlib<span class="token punctuation">(</span>SDL_gesture.c.o<span class="token punctuation">)</span>:<span class="token punctuation">(</span>.bss.WAYLAND_wl_proxy_get_user_data+0x0<span class="token punctuation">)</span>: multiple definition of <span class="token variable"><span class="token variable">`</span>WAYLAND_wl_proxy_get_user_data&#x27;<span class="token punctuation">;</span> /tmp/rustcSwsrGo/libsdl2_sys-ab14be8f9d7d1911.rlib<span class="token punctuation">(</span>SDL_events.c.o<span class="token punctuation">)</span>:<span class="token punctuation">(</span>.bss.WAYLAND_wl_proxy_get_user_data+0x0<span class="token punctuation">)</span>: first defined here </span></span><span class="code-line"><span class="token variable"> /usr/bin/ld: /tmp/rustcSwsrGo/libsdl2_sys-ab14be8f9d7d1911.rlib<span class="token punctuation">(</span>SDL_gesture.c.o<span class="token punctuation">)</span>:<span class="token punctuation">(</span>.bss.WAYLAND_wl_proxy_set_user_data+0x0<span class="token punctuation">)</span>: multiple definition of <span class="token variable">`</span></span>WAYLAND_wl_proxy_set_user_data<span class="token string">&#x27;; /tmp/rustcSwsrGo/libsdl2_sys-ab14be8f9d7d1911.rlib(SDL_events.c.o):(.bss.WAYLAND_wl_proxy_set_user_data+0x0): first defined here </span></span><span class="code-line"><span class="token string"> /usr/bin/ld: /tmp/rustcSwsrGo/libsdl2_sys-ab14be8f9d7d1911.rlib(SDL_gesture.c.o):(.bss.WAYLAND_wl_proxy_add_listener+0x0): multiple definition of `WAYLAND_wl_proxy_add_listener&#x27;</span><span class="token punctuation">;</span> /tmp/rustcSwsrGo/libsdl2_sys-ab14be8f9d7d1911.rlib<span class="token punctuation">(</span>SDL_events.c.o<span class="token punctuation">)</span>:<span class="token punctuation">(</span>.bss.WAYLAND_wl_proxy_add_listener+0x0<span class="token punctuation">)</span>: first defined here </span></code></pre></div><p>Google一下,发现是这个代码没有兼容最新的GCC 10</p><p>因为老灯用的Fedora, GCC 版本是较新的:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ gcc <span class="token variable parameter">--version</span> </span><span class="code-line">gcc <span class="token punctuation">(</span>GCC<span class="token punctuation">)</span> <span class="token number">10.2</span>.1 <span class="token number">20200723</span> <span class="token punctuation">(</span>Red Hat <span class="token number">10.2</span>.1-1<span class="token punctuation">)</span> </span><span class="code-line">Copyright <span class="token punctuation">(</span>C<span class="token punctuation">)</span> <span class="token number">2020</span> Free Software Foundation, Inc. </span><span class="code-line">This is <span class="token function">free</span> software<span class="token punctuation">;</span> see the <span class="token builtin class-name">source</span> <span class="token keyword">for</span> copying conditions. There is NO </span><span class="code-line">warranty<span class="token punctuation">;</span> not even <span class="token keyword">for</span> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. </span></code></pre></div><p>当然,老灯很快发现不只我一个人有遇到这个问题,<a href="https://github.com/Kethku/neovide/issues/306">https://github.com/Kethku/neovide/issues/306</a></p><p>有个workaround 是, <code>cargo clean &amp;&amp; CFLAGS=&quot;-fcommon -fPIE&quot; cargo build</code></p><p>当然,要从根本上解决这个问题,还得是从上游的C绑定库<a href="https://crates.io/crates/sdl2">sdl2</a>修复: <a href="https://github.com/Rust-SDL2/rust-sdl2/pull/1010">https://github.com/Rust-SDL2/rust-sdl2/pull/1010</a></p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">From 9781d21b57b0fb8d70d0ac58022047730b9b62a7 Mon Sep 17 00:00:00 2001 </span><span class="code-line">From: Jack Frost &lt;[email protected]&gt; </span><span class="code-line">Date: Mon, 15 Jun 2020 22:03:16 +0000 </span><span class="code-line">Subject: [PATCH] adds necessary libs for gcc10 to work </span><span class="code-line"> </span><span class="code-line deleted"><span class="token coord">---</span> </span><span class="code-line"><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line">sdl2-sys/build.rs | 14 ++++++++++++++ </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line">1 file changed, 14 insertions(+) </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span></span> </span><span class="code-line">diff --git a/sdl2-sys/build.rs b/sdl2-sys/build.rs </span><span class="code-line">index 2af74b1c83..4f3a472c27 100644 </span><span class="code-line deleted"><span class="token coord">--- a/sdl2-sys/build.rs</span> </span><span class="code-line inserted"><span class="token coord">+++ b/sdl2-sys/build.rs</span> </span><span class="code-line">@@ -267,6 +267,20 @@ fn compile_sdl2(sdl2_build_path: &amp;Path, target_os: &amp;str) -&gt; PathBuf { </span><span class="code-line"><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> let mut cfg = cmake::Config::new(sdl2_build_path); </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line"> cfg.profile(&quot;release&quot;); </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line"> </span></span></span><span class="code-line inserted"><span class="token unchanged"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> #[cfg(target_os = &quot;linux&quot;)] </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> { </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> use version_compare::Version; </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> if let Ok(version) = std::process::Command::new(&quot;cc&quot;).arg(&quot;-dumpversion&quot;).output() { </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> let local_ver = Version::from(std::str::from_utf8(&amp;version.stdout).unwrap()).unwrap(); </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> let affected_ver = Version::from(&quot;10&quot;).unwrap(); </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> if local_ver &gt;= affected_ver { </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> cfg.cflag(&quot;-fcommon&quot;); </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> cfg.cflag(&quot;-fPIE&quot;); </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> } </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> } </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> } </span></span></span><span class="code-line inserted"><span class="token inserted inserted-sign"><span class="token line"></span><span class="token inserted prefix">+</span><span class="token line"> </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> if target_os == &quot;windows-gnu&quot; { </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line"> cfg.define(&quot;VIDEO_OPENGLES&quot;, &quot;OFF&quot;); </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line"> } </span></span></span></code></pre></div><p>而它的引入是在 <a href="https://github.com/aclysma/skulpin/blob/master/skulpin-renderer-sdl2/Cargo.toml">https://github.com/aclysma/skulpin/blob/master/skulpin-renderer-sdl2/Cargo.toml</a>, 因此需要改 <code>skulpin</code></p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line deleted"><span class="token coord">---</span> </span><span class="code-line">diff --git a/skulpin-renderer-sdl2/Cargo.toml b/skulpin-renderer-sdl2/Cargo.toml </span><span class="code-line">index 3dec89f..b2afdea 100644 </span><span class="code-line deleted"><span class="token coord">--- a/skulpin-renderer-sdl2/Cargo.toml</span> </span><span class="code-line inserted"><span class="token coord">+++ b/skulpin-renderer-sdl2/Cargo.toml</span> </span><span class="code-line">@@ -17,6 +17,6 @@ categories = [&quot;graphics&quot;, &quot;gui&quot;, &quot;multimedia&quot;, &quot;rendering&quot;, &quot;visualization&quot;] </span><span class="code-line"><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line">[dependencies] </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line">skulpin-renderer = { version = &quot;0.3&quot;, path = &quot;../skulpin-renderer&quot; } </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line"> </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token prefix deleted">-</span><span class="token line">sdl2 = { version = &quot;&gt;=0.33&quot; } </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line">sdl2 = { version = &quot;&gt;=0.34.3&quot; } </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line">log=&quot;0.4&quot; </span></span></span></code></pre></div><p>然后 <code>cargo clean &amp;&amp; cargo update &amp;&amp; cargo build</code></p><p>然后一跑,崩了:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ ./target/debug/neovide </span><span class="code-line">Ignored client <span class="token builtin class-name">type</span> property: <span class="token string">&quot;methods&quot;</span> </span><span class="code-line">Ignored client <span class="token builtin class-name">type</span> property: <span class="token string">&quot;attributes&quot;</span> </span><span class="code-line">X Error of failed request: BadDrawable <span class="token punctuation">(</span>invalid Pixmap or Window parameter<span class="token punctuation">)</span> </span><span class="code-line"> Major opcode of failed request: <span class="token number">148</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> Minor opcode of failed request: <span class="token number">4</span> </span><span class="code-line"> Resource <span class="token function">id</span> <span class="token keyword">in</span> failed request: 0x3e0000c </span><span class="code-line"> Serial number of failed request: <span class="token number">239</span> </span><span class="code-line"> Current serial number <span class="token keyword">in</span> output stream: <span class="token number">247</span> </span></code></pre></div><p>貌似是跟 <code>Vulkan</code> 和 <code>Wayland</code> 相关。<a href="https://github.com/aclysma/skulpin">skulpin</a> 的描述是:</p><blockquote><p>Skia + Vulkan = Skulpin This crate provides an easy option for drawing hardware-accelerated 2D by combining vulkan and skia.</p></blockquote><p>根据 <a href="https://rpmfusion.org/Howto/NVIDIA#Vulkan">https://rpmfusion.org/Howto/NVIDIA#Vulkan</a>, vulkan貌似要手动安装一下的,试试看:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> dnf list <span class="token variable parameter">--installed</span> <span class="token operator">|</span> <span class="token function">grep</span> vulkan </span><span class="code-line"><span class="token punctuation">[</span>sudo<span class="token punctuation">]</span> password <span class="token keyword">for</span> ttys3: </span><span class="code-line">mesa-vulkan-drivers.x86_64 <span class="token number">20.1</span>.6-1.fc32 @updates </span><span class="code-line">vulkan-loader.x86_64 <span class="token number">1.2</span>.135.0-1.fc32 @updates </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">sudo</span> dnf <span class="token function">install</span> vulkan </span><span class="code-line">Scooter Software <span class="token number">0.0</span> B/s <span class="token operator">|</span> <span class="token number">0</span> B 00:00 </span><span class="code-line">Last metadata expiration check: <span class="token number">1</span>:10:21 ago on Sat <span class="token number">29</span> Aug <span class="token number">2020</span> 04:13:18 PM CST. </span><span class="code-line">Package vulkan-loader-1.2.135.0-1.fc32.x86_64 is already installed. </span><span class="code-line">Dependencies resolved. </span><span class="code-line">Nothing to do. </span><span class="code-line">Complete<span class="token operator">!</span> </span><span class="code-line"> </span></code></pre></div><p>结果发现是已安装的。</p><p>可能是只支持Wayland吧,我现在用的从rpmfusion源安装的N卡私有驱动,只能用X11的。算了。</p><p>试试另一个 1.1K star的 <a href="https://github.com/vhakulinen/gnvim">https://github.com/vhakulinen/gnvim</a>, UI主要是基于 <code>libwebkit2gt</code> 和 GTK. 编译很顺利。</p><p>运行发现,当一行中同时有中文和英文时,英文显示不正常。英文重叠显示在中文上了。</p><p>还是妥妥地在terminal里跑吧,别整GUI了。</p> Sat, 29 Aug 2020 08:56:41 GMT ttyS3 neovimvimgui https://ttys3.dev/blog/git-config-conditional-includes-usage Git 配置文件中 Conditional Includes 的使用 https://ttys3.dev/blog/git-config-conditional-includes-usage <h2 id="使用场景"><a href="#使用场景" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>使用场景</h2><p>个人电脑里同时有公司的项目的源码和自己的开源项目的源码,而一般在公司使用的<code>name</code>和<code>email</code>配置跟家用的都是区分开的。 如何实现,在进入公司项目的目录提交git commit时让Git自动使用公司邮箱和名称,而在进入其它目录时则保持家用的配置呢?</p><p>答案就是:Git Conditional Includes</p><h2 id="使用conditional-includes"><a href="#使用conditional-includes" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>使用Conditional Includes</h2><p>老灯的需求比较简单,只有home和work两种情况。因此,配置如下:</p><p><code>~/repo/go/work</code> 目录是公司项目的根目录,下面会有多层子目录。 除此之外,其它repo都默认是老灯自己的个人项目。</p><p><code>~/.gitconfig</code> 作为配置的入口,根据条件引入其它配置:</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line"><span class="token comment"># 默认的 user.name 和 user.email 配置</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">include</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">path</span> <span class="token punctuation">=</span> <span class="token attr-value value">~/.gitconfig_home</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 如果是公司项目的目录,则使用另一个配置</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">includeIf &quot;gitdir:~/repo/go/work/&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">path</span> <span class="token punctuation">=</span> <span class="token attr-value value">~/.gitconfig_work</span> </span></code></pre></div><p>这个配置非常简单,默认先导入<code>~/.gitconfig_home</code>中的Git配置, 如果repo是在<code>~/repo/go/work/</code>之下(包括其下所有子目录), 则导入 <code>~/.gitconfig_work</code> 中的Git配置</p><p><code>~/.gitconfig_home</code> 内容如下:</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">user</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">name</span> <span class="token punctuation">=</span> <span class="token attr-value value">荒野無燈</span> </span><span class="code-line"> <span class="token attr-name key">email</span> <span class="token punctuation">=</span> <span class="token attr-value value">[email protected]</span> </span><span class="code-line"> <span class="token attr-name key">signingkey</span> <span class="token punctuation">=</span> <span class="token attr-value value">BE78EC4026F094F8</span> </span></code></pre></div><p><code>~/.gitconfig_work</code>内容如下:</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">user</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">name</span> <span class="token punctuation">=</span> <span class="token attr-value value">姓名</span> </span><span class="code-line"> <span class="token attr-name key">email</span> <span class="token punctuation">=</span> <span class="token attr-value value">[email protected]</span> </span><span class="code-line"> <span class="token attr-name key">signingkey</span> <span class="token punctuation">=</span> <span class="token attr-value value">xxxxxxxxxxxxxxx</span> </span></code></pre></div><p>Conditional Includes 主要支持三个关键字:<code>gitdir</code>, <code>gitdir/i</code> 和 <code>onbranch</code></p><p>这里老灯只用到了 <code>gitdir</code>,它的忽略大小写版则是<code>gitdir/i</code>了。</p><p>这里有一些细节需要注意, Git文档说得很清楚:</p><p><code>gitdir:</code> 关键字用于glob匹配模式. 如果 <code>.git</code> 目录匹配,则满足include的条件.</p><p><code>.git</code>的位置可被自动检测,或者来自<code>$GIT_DIR</code>环境变量。</p><ul><li>如果 pattern 以 <code>~/</code>开头,则<code>~</code>会被自动替换成 <code>$HOME</code> 的值。</li><li>如果 pattern 以 <code>./</code>开头,则会被自动替换包含当前配置文件的目录。</li><li>如果 pattern 不是以<code>~/</code>, <code>./</code> 或 <code>/</code>中的任意一个开头,则<code>**/</code>会被自动前置。比如<code>foo/bar</code>实际上是变成<code>**/foo/bar</code>,能匹配<code>/any/path/to/foo/bar</code></li><li>如果 pattern 以 <code>/</code> 结尾,则<code>**</code>会被自动添加上。比如<code>foo/</code> 会变成 <code>foo/**</code>,换句话说,它会匹配<code>foo</code>以及递归地匹配其下的所有目录。因此我们没必要显式地写<code>foo/**</code></li></ul><p>另外, 老灯这里的情况比较简单,因此,其实只需要一个<code>includeIf</code>即可:</p><div class="relative"><pre><code class="language-ini code-highlight"><span class="code-line"><span class="token comment"># 默认的 user.name 和 user.email 配置</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">user</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">name</span> <span class="token punctuation">=</span> <span class="token attr-value value">荒野無燈</span> </span><span class="code-line"> <span class="token attr-name key">email</span> <span class="token punctuation">=</span> <span class="token attr-value value">[email protected]</span> </span><span class="code-line"> <span class="token attr-name key">signingkey</span> <span class="token punctuation">=</span> <span class="token attr-value value">BE78EC4026F094F8</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 如果是公司项目的目录,则使用另一个配置</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">includeIf &quot;gitdir:~/repo/go/work/&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">path</span> <span class="token punctuation">=</span> <span class="token attr-value value">~/.gitconfig_work</span> </span></code></pre></div><p>当然,老灯用一个默认的<code>include</code>的好处是,分享 <code>.gitconfig</code> 给别人的时候, 就默认不会leak 用户名和email了。</p><h2 id="本文参考"><a href="#本文参考" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>本文参考</h2><p><a href="https://blog.jiayu.co/2019/02/conditional-git-configuration/">https://blog.jiayu.co/2019/02/conditional-git-configuration/</a></p><p><a href="https://blog.thomasheartman.com/posts/modularizing-your-git-config-with-conditional-includes">https://blog.thomasheartman.com/posts/modularizing-your-git-config-with-conditional-includes</a></p><p><a href="https://git-scm.com/docs/git-config#Documentation/git-config.txt-codegitdircode">https://git-scm.com/docs/git-config#Documentation/git-config.txt-codegitdircode</a></p><p><a href="https://dzone.com/articles/how-to-use-gitconfigs-includeif">https://dzone.com/articles/how-to-use-gitconfigs-includeif</a></p> Sun, 16 Aug 2020 13:13:40 GMT ttyS3 Gitconfig https://ttys3.dev/blog/charles Charles使用技巧 https://ttys3.dev/blog/charles <h2 id="1-linux-下-hidpi-问题"><a href="#1-linux-下-hidpi-问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. Linux 下 HiDPI 问题</h2><p>OS: Fedora 32 (Workstation Edition) GNOME 版本:3.36.3 Charles Proxy 版本: v4.5.6</p><p>通常在 GNOME3 下我们会将 Display 的 Scale 调成 <code>200%</code> (当前还不支持非整数倍数设置) 来解决4K分辨率问题,如下图:</p><div><img alt="" src="https://ttys3.dev/static/assets/gnome3-display-scale-2020-07-20-23-57-26-CMNNVYUS.png" width="1920" height="909"/></div><p>Charles官方也宣称它已经支持HiDPI了,但是实际使用却发现没有自动识别HiDPI,为什么呢?</p><p>我们看看<code>/usr/bin/charles</code> 这个启动脚本:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># HiDPI</span> </span><span class="code-line"><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token variable parameter">-x</span> /usr/bin/gsettings <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span> </span><span class="code-line"> <span class="token variable assign-left">GDK_SCALE</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span>/usr/bin/gsettings get org.gnome.desktop.interface scaling-factor <span class="token operator">|</span> <span class="token function">awk</span> <span class="token string">&#x27;{print $2}&#x27;</span><span class="token variable">)</span></span> </span><span class="code-line"> <span class="token builtin class-name">export</span> GDK_SCALE </span><span class="code-line"><span class="token keyword">fi</span> </span></code></pre></div><p>如果我们执行<code>gsettings list-recursively org.gnome.desktop.interface</code> 看看就会发现,这个<code>scaling-factor</code>(虽然是有这个key的)并没有被设置。因此,<code>/usr/bin/gsettings get org.gnome.desktop.interface scaling-factor</code> 的结果是:<code>uint32 0</code></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ /usr/bin/gsettings describe org.gnome.desktop.interface scaling-factor </span><span class="code-line">Integer factor used to scale windows by. For use on high-dpi screens. <span class="token number">0</span> means pick automatically based on monitor. </span></code></pre></div><p>根据 <a href="https://wiki.archlinux.org/index.php/HiDPI#GNOME">ArchLinux 的文档</a>,这两种设置方法应该是等效的(但是上面的结果表示, 通过图片界面设置的display scale, 不会反应到 <code>scaling-factor</code>):</p><blockquote><p>To enable HiDPI, navigate to <strong>Settings &gt; Devices &gt; Displays &gt; Scale</strong> and choose an appropriate value. Or, use <strong>gsettings</strong>:</p></blockquote><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">$ gsettings <span class="token builtin class-name">set</span> org.gnome.settings-daemon.plugins.xsettings overrides <span class="token string">&quot;[{&#x27;Gdk/WindowScalingFactor&#x27;, &lt;2&gt;}]&quot;</span> </span><span class="code-line">$ gsettings <span class="token builtin class-name">set</span> org.gnome.desktop.interface scaling-factor <span class="token number">2</span> </span></code></pre></div><blockquote><p>Note: GNOME only allows integer scaling numbers to be set. 1 = 100%, 2 = 200%, etc. See Fractional Scaling below.</p></blockquote><p>因此,这里针对 Charles 最简单的解决办法就是执行 <code>gsettings set org.gnome.desktop.interface scaling-factor 2</code></p><h2 id="2-启用-https-抓包"><a href="#2-启用-https-抓包" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. 启用 HTTPS 抓包</h2><div><img alt="" src="https://ttys3.dev/static/assets/charles-enable-ssl-2020-07-21-00-20-27-AOB3FYWN.png" width="1150" height="1000"/></div><p>光启用了这个还不行,对于 iOS 来说,还得安装 Charles 的根证书。</p><p>先将 iOS WLAN 的 HTTP 代理设置成 <code>IP:8888</code> (8888是Charles的默认http代理监听端口), 然后在手机浏览器里打开 <code>chls.pro/ssl</code> 下载证书。</p><p>iOS 10 及以上版本必须额外操作来信任此证书。</p><p>我当前的iOS 版本为 13.4.1 , 不同的版本设置可能不太相同。这个入口还挺深的。</p><div><img alt="" src="https://ttys3.dev/static/assets/ios13-charles-ssl-2020-07-21-00-29-04-3LP34VHT.png" width="760" height="1018"/></div><div><img alt="" src="https://ttys3.dev/static/assets/ios13-charles-ssl-2-2020-07-21-00-29-45-472MNQRA.png" width="740" height="434"/></div><div><img alt="" src="https://ttys3.dev/static/assets/ios13-charles-ssl-3-2020-07-21-00-30-10-7A53OIIP.png" width="738" height="648"/></div><div><img alt="" src="https://ttys3.dev/static/assets/ios13-charles-ssl-4-2020-07-21-00-30-33-YXYNEKFD.png" width="742" height="634"/></div><div><img alt="" src="https://ttys3.dev/static/assets/ios13-charles-ssl-5-2020-07-21-00-30-59-FXY6CVWT.png" width="738" height="622"/></div><h2 id="3-过滤掉部分域名或只抓取部分域名"><a href="#3-过滤掉部分域名或只抓取部分域名" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. 过滤掉部分域名或只抓取部分域名</h2><p>右击一个请求,选择 ignore 即会自动将此URL添加到<code>Recording Settings</code> 里的 <code>Exclude</code>, 一般我们都会想直接过滤整个域名,这个时候只需要“双击”编辑一下这个自动添加的项,去除 <code>Path</code> 和 <code>Query</code> 即可。</p><div><img alt="" src="https://ttys3.dev/static/assets/charles-edit-exclude-item-2020-07-21-00-35-46-WMM4ZVSF.png" width="1100" height="896"/></div><p>如果反过来,只想要白名单抓取的话,设置 <code>Include</code> 即可。</p><p>这些条目还可以非常方便地导出,方便导入到其它机器。</p><h2 id="4-protobuf-自动解包"><a href="#4-protobuf-自动解包" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4. Protobuf 自动解包</h2><p>通过<code>Viewer Mappings</code>设置,我们可以让Charles自动选择对应的消息类型解包, 而不需要每次请求完手动选项相应的消息类型。</p><p>以下是一个demo设置,这个请求发送的数据类型为json,但是响应是protobuf, 我们通过设置特定的 <code>Path</code> 来限制这个规则只应用于此 API:</p><div><img alt="" src="https://ttys3.dev/static/assets/charles-viewer-mappings-2020-07-21-00-38-41-N45XBNGT.png" width="1338" height="1172"/></div><p>如果是自定义的protobuf包,则可以通过<code>View</code> -&gt; <code>Protobuf Settings</code>添加 *.desc 描述文件.</p><p>描述文件可通过以下命令生成:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">protoc <span class="token variable parameter">-oModel.desc</span> Model.proto </span></code></pre></div><p>需要注意的是,请求或响应头的<code>Content-Type</code>字段必须要是<code>application/x-protobuf</code> 或 <code>application/x-google-protobuf</code> , Charles才会自动识别为probobuf包</p><p>更多信息可参考 <a href="https://www.charlesproxy.com/documentation/using-charles/protocol-buffers/">https://www.charlesproxy.com/documentation/using-charles/protocol-buffers/</a></p> Mon, 20 Jul 2020 15:53:46 GMT ttyS3 charlesproxyhttpdebugprotobuf https://ttys3.dev/blog/git-splitting-a-subfolder-out-into-a-new-repository Git拆分子目录为新仓库 https://ttys3.dev/blog/git-splitting-a-subfolder-out-into-a-new-repository <p>en title: Git Splitting a Subfolder Out Into a New Repository</p><h2 id="需求"><a href="#需求" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>需求</h2><p>某个历史悠久的“大”Git仓库(很大很大。。。)要拆分成很多小仓库。</p><p>至于为什么会有这种“大”仓库的存在,表问我。。。 it&#x27;s about project history</p><h2 id="为什么要这样做"><a href="#为什么要这样做" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>为什么要这样做?</h2><ul><li>查bug的时候不再需要同时切换新旧两个仓库交叉查看历史commit记录</li><li>可以保留被拆分目录下文件的完整提交记录,方便他人阅读代码和理解代码</li></ul><h2 id="这样做会不会增加迁移的负担"><a href="#这样做会不会增加迁移的负担" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>这样做会不会增加迁移的负担?</h2><p>不会,绝对不会。一条命令即可搞定 (git filter-repo xxxxx)。</p><h2 id="准备工作"><a href="#准备工作" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>准备工作</h2><p><code>git-filter-repo</code> 现在是Git官方推荐的工具(git自带的<code>filter-branch</code>已经不被推荐使用了,速度慢又不好用)。</p><blockquote><p>git filter-repo is now recommended by the git project instead of git filter-branch. <a href="https://git-scm.com/docs/git-filter-branch#_warning">https://git-scm.com/docs/git-filter-branch#_warning</a></p></blockquote><blockquote><p>注: github 官方文档里也有个拆分子目录的教程,那个是用的<code>filter-branch</code>, 已经过时了,不用看了。</p></blockquote><h3 id="安装filter-repo"><a href="#安装filter-repo" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装filter-repo</h3><p>安装<code>git-filter-repo</code> 只需要执行一次:</p><p>pip3的模块带的可执行文件默认情况下会安装到 <code>$HOME/.local/bin</code>, 因此要把<code>$HOME/.local/bin</code>加入<code>PATH</code> 环境变量。</p><p>如果你的系统有不同的配置,以你自己的系统为准,比如Mac之类的, 如果偏爱brew, 可以参考官方文档 <a href="https://github.com/newren/git-filter-repo/blob/main/INSTALL.md">https://github.com/newren/git-filter-repo/blob/main/INSTALL.md</a></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment">#安装 filter-repo</span> </span><span class="code-line">pip3 <span class="token function">install</span> <span class="token variable parameter">--user</span> git-filter-repo </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 将以下环境变量配置放到你自己正在使用的shell的rc配置文件中(如.bashrc, .zshrc 等)</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left"><span class="token constant environment">PATH</span></span><span class="token operator">=</span><span class="token string">&quot;<span class="token constant environment">$HOME</span>/.local/bin:<span class="token constant environment">$PATH</span>&quot;</span> </span></code></pre></div><h3 id="大仓库准备只需要执行一次"><a href="#大仓库准备只需要执行一次" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>大仓库准备(只需要执行一次):</h3><p>大仓库作为历史仓库,需要拆分成很多小仓库,原则上我们不会再添加新代码了。</p><p>首先,我们将大仓库<code>THE_BIG_REPO</code> clone一份,保存为<code>THE_BIG_REPO.orig</code>, 避免以后每次要从github clone,速度太慢。</p><p>这里 <code>~/repo/go/split-work</code> 是我用于迁移专门准备的目录。</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">  <span class="token operator">~</span><span class="token operator">/</span>repo<span class="token operator">/</span>go<span class="token operator">/</span>split<span class="token operator">-</span>work </span><span class="code-line">❯ cd <span class="token operator">~</span><span class="token operator">/</span>repo<span class="token operator">/</span>go<span class="token operator">/</span>split<span class="token operator">-</span>work </span><span class="code-line">❯ git clone git@github<span class="token punctuation">.</span><span class="token property-access">com</span><span class="token operator">:</span><span class="token maybe-class-name">VendorName</span><span class="token operator">/</span><span class="token constant">THE_BIG_REPO</span><span class="token punctuation">.</span><span class="token property-access">git</span> <span class="token constant">THE_BIG_REPO</span><span class="token punctuation">.</span><span class="token property-access">orig</span> </span></code></pre></div><p><code>THE_BIG_REPO.orig</code> 作为拆分的原始仓库, 其它拆分<strong>每次</strong>从这个目录clone</p><hr/><h2 id="迁移步骤"><a href="#迁移步骤" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>迁移步骤</h2><h3 id="1拆分子目录为仓库"><a href="#1拆分子目录为仓库" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1.拆分子目录为仓库</h3><p>以 xxx_write_agent 这个子目录(实际上它是一个单独的微服务)为例。</p><p><code>~/repo/go/split-work</code> 是我用于迁移专门准备的目录。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">cd</span> ~/repo/go/split-work/ </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 将我们之前clone好的大仓库,clone一份到当前目录,为方便识别,重命名目录为 xxx_write_agent</span> </span><span class="code-line"><span class="token function">git</span> clone ~/repo/go/split-work/THE_BIG_REPO.orig xxx_write_agent </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 进入 xxx_write_agent</span> </span><span class="code-line"><span class="token builtin class-name">cd</span> xxx_write_agent/ </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 20200723 修正:git checkout xxx 不能执行,执行后会提示 Refusing to overwrite repo history since this does not look like a fresh clone.</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 好了,关键的操作来了</span> </span><span class="code-line"><span class="token comment"># 现在我们所在的 xxx_write_agent 目录,实际上是整个老仓库</span> </span><span class="code-line"><span class="token comment"># 假设我们要迁移的 xxx_write_agent 目录相对于当前目录的路径是: a-parent-path/project/another-pkg/xxx_write_agent</span> </span><span class="code-line"><span class="token comment"># 执行以下命令,将自动干掉其它目录,只保留 xxx_write_agent 目录及其commit记录</span> </span><span class="code-line"><span class="token function">git</span> filter-repo --subdirectory-filter a-parent-path/project/another-pkg/xxx_write_agent </span></code></pre></div><p>好了,现在的 xxx_write_agent 仓库已经是名副其实的 xxx_write_agent 了。</p><p>接下来我们要做一些清理工作</p><hr/><h3 id="2清理工作"><a href="#2清理工作" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2.清理工作</h3><p>清理除 <code>dev</code> 之外的其它branch</p><p>由于在老仓库,我们的 <code>dev</code> 是最新的分支,因此,我们只需要保留 <code>dev</code> 分支即可。其它branch和tags 如果推送到了新仓库,会带来干扰。</p><p>值得高兴的是, 之前的仓库没有发过任何版本,也不存在任何tag, 因此我们可以省掉清tag这一步了。只需要清除branch。</p><p>如果你的情况不同,请按你自己的来,比如,你的仓库很可能是 master 是最新的。</p><blockquote><p>以下命令中<code>git br</code> 是一个git别名, 有人可能配置成了shell的别名,比如<code>gbr</code>, 如果没有的,请自行把它换成原版的完整命令 <code>git branch</code></p></blockquote><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">git</span> checkout dev <span class="token operator">&amp;&amp;</span> <span class="token function">git</span> br <span class="token operator">|</span> <span class="token function">grep</span> <span class="token variable parameter">-v</span> <span class="token string">&#x27;*&#x27;</span> <span class="token operator">|</span> <span class="token function">xargs</span> -I<span class="token string">&#x27;{}&#x27;</span> <span class="token function">git</span> br <span class="token variable parameter">-D</span> <span class="token string">&#x27;{}&#x27;</span> </span></code></pre></div><p>将原dev(最新分支)重命名为 <code>develop</code> (主要是用于git flow)</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">git</span> br <span class="token variable parameter">-m</span> dev develop </span></code></pre></div><p>在dev的基础上创建 master 分支 (主要是用于git flow, 初始化时必须有master分支):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">git</span> br master </span></code></pre></div><p>初始化 <code>git flow</code>:</p><p>(注, 我这里用了默认配置,这个是我在全局<code>.gitconfig</code>中已经配置好了,请参见末尾&quot;git flow 相关配置&quot;)</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">git</span> flow init <span class="token variable parameter">-d</span> </span><span class="code-line">Using default branch names. </span><span class="code-line"> </span><span class="code-line">Which branch should be used <span class="token keyword">for</span> bringing forth production releases? </span><span class="code-line"> - develop </span><span class="code-line"> - master </span><span class="code-line">Branch name <span class="token keyword">for</span> production releases: <span class="token punctuation">[</span>master<span class="token punctuation">]</span> </span><span class="code-line"> </span><span class="code-line">Which branch should be used <span class="token keyword">for</span> integration of the <span class="token string">&quot;next release&quot;</span>? </span><span class="code-line"> - develop </span><span class="code-line">Branch name <span class="token keyword">for</span> <span class="token string">&quot;next release&quot;</span> development: <span class="token punctuation">[</span>develop<span class="token punctuation">]</span> </span><span class="code-line">Hooks and filters directory? <span class="token punctuation">[</span>/home/ttys3/repo/go/split-work/split/THE_BIG_REPO/.git/hooks<span class="token punctuation">]</span> </span></code></pre></div><p>给原始代码新建一 <code>0.0.1</code> 版本,记录一下这是原始迁移过来的代码。后续的发版都是从 <code>0.1.0</code> 开始,因此可以很好的区分哪些是历史commit.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">git</span> flow release start <span class="token number">0.0</span>.1 <span class="token operator">&amp;&amp;</span> <span class="token function">git</span> flow release finish <span class="token string">&#x27;0.0.1&#x27;</span> </span></code></pre></div><p>message内容为:</p><blockquote><p>split subdir to repo from github.com/VendorName/THE_BIG_REPO dev branch</p></blockquote><p>好了,到这里,拆分并保留commit记录的任务已经完成了。</p><p>其实核心的命令只有一条:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">git</span> filter-repo --subdirectory-filter 需要保留的子目录的相对路径 </span></code></pre></div><hr/><h2 id="git-flow-相关配置"><a href="#git-flow-相关配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>git flow 相关配置</h2><p>编辑全局<code>.gitconfig</code> 配置文件,增加git flow 相关配置:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">gitflow &quot;prefix&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">feature</span> <span class="token punctuation">=</span> <span class="token attr-value value">feature/</span> </span><span class="code-line"> <span class="token attr-name key">bugfix</span> <span class="token punctuation">=</span> <span class="token attr-value value">bugfix/</span> </span><span class="code-line"> <span class="token attr-name key">release</span> <span class="token punctuation">=</span> <span class="token attr-value value">release/</span> </span><span class="code-line"> <span class="token attr-name key">hotfix</span> <span class="token punctuation">=</span> <span class="token attr-value value">hotfix/</span> </span><span class="code-line"> <span class="token attr-name key">support</span> <span class="token punctuation">=</span> <span class="token attr-value value">support/</span> </span><span class="code-line"> <span class="token attr-name key">versiontag</span> <span class="token punctuation">=</span> <span class="token attr-value value">v</span> </span></code></pre></div> Mon, 20 Jul 2020 15:27:57 GMT ttyS3 gitSubfolderSplit https://ttys3.dev/blog/do-not-use-alpine-in-production-environment 不要在生产环境中使用alpine基础镜像 -- 容器基础镜像的选择 https://ttys3.dev/blog/do-not-use-alpine-in-production-environment <blockquote><p>You will NOT fucked up by alpine if you do not use alpine</p><p>alpine没有docker鼓吹得那么美好</p><p>少20M体积对你来说真的很重要?</p></blockquote><p>en: Do Not Use Alpine as Container Base Image in Production Environment</p><p>本文写作日期为<strong>2020年3月26日</strong></p><h2 id="关于server的选择"><a href="#关于server的选择" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>关于server的选择</h2><p>虽然说容器与host机的Linux发行版关系不大。 但是,抛开容器不说,现在,我们来做一个假设,假设我们没有使用容器,使用裸机跑Linux server, 会选择使用哪个发行版? 没错,怎么选都轮不到Alpine吧。</p><p>server的话比较注重支持期限, 基本上大版本定下来,后面升级的可能性非常小. 比如很多项目用了CentOS6,基本上不大可能会升级到CentOS7和CentOS8 那么问题来了,大版本不升级,要是安全更新也停止了,服务器就处于危险状态了.所以,支持期限比较重要.</p><p>fedora的Life Cycle是6个月发一个大版,当然不适合做server.</p><p>centos是跟rhel走,并且更新稍落后于rhel的,差不多是 10 年</p><p>debian 非LTS一般是一到两年的样子, LTS 是至少5年。<a href="https://wiki.debian.org/DebianReleases">https://wiki.debian.org/DebianReleases</a> 另外需要注意的是:Debian LTS is not handled by the Debian security team, but by a separate group of volunteers and companies interested in making it a success. Debian LTS其实主要是 Freexian 在维护. <a href="https://wiki.debian.org/LTS">https://wiki.debian.org/LTS</a> <a href="https://wiki.debian.org/LTS/Funding">https://wiki.debian.org/LTS/Funding</a> 另外, Freexian 这个公司还提供付费的ELTS <a href="https://www.freexian.com/services/debian-lts.html">https://www.freexian.com/services/debian-lts.html</a></p><p>centos后面有rhel, ubuntu server 背后有Canonical (Canonical | The company behind Ubuntu), 这两个server版都带有商业的相关背景. 因此一些卖系统级软件和服务的公司,往往选择debian stable来发布他们的产品,比如一些NAS厂家. 网上一些开源的NAS系统实现, 很多也是基于debian的:典型的比如Open Media Vault 是基于debian的.<br/>专门为kvm虚拟机和Linux容器而生的操作系统: Proxmox VE (一般简称为PVE) 也是基于debian的. 一个特例是:unRAID 这个收费的NAS系统,是基于Slackware Linux发行版的</p><p>ubuntu lts 支持也是5年. A new LTS version is released every two years. In previous releases, a Long Term Support (LTS) version had three years support on Ubuntu (Desktop) and five years on Ubuntu Server. Starting with Ubuntu 12.04 LTS, both versions received five years support. There is no extra fee for the LTS version; we make our very best work available to everyone on the same free terms. Upgrades to new versions of Ubuntu are and always will be free of charge. <a href="https://wiki.ubuntu.com/LTS">https://wiki.ubuntu.com/LTS</a></p><p>所以,对比之下, 不用花钱就能得到10年支持的CentOS,当然很多人喜欢. 并不是说rpm这个包管理有多优秀,事实上老灯觉得pacman才是最棒的,deb包( apt-get)次之. 如果你写过pacman的 PKGBUILD 文件你就会发现它有多简洁好用. deb包构建其实也比较方便. rpm可能是这几个里面最麻烦的.</p><h2 id="容器基础镜像的选择"><a href="#容器基础镜像的选择" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>容器基础镜像的选择</h2><p>基础镜像包含了应用运行需要的环境,对于使用裸机跑Linux来说,选择哪个发行版很重要,而对于用容器跑应用来说, 选择哪个镜像作为基础镜像构建应用,以及选择哪个镜像作为基础镜像来运行应用,也显得尤其重要。</p><p>容器的出现,使得应用的部署变得非常灵活. 应用不再依赖host机的软件包版本,可以放飞自我了. 说到容器,不得不提到docker, 说到docker你又很难不看到alpine这个字眼. 如果不是docker, 我可能这辈子都不会碰alpine linux这种东西.</p><p>据说docker早期的官方镜像都是基于debian发布的,直到有一天,发生了一件事:</p><blockquote><p>Hykes (Docker’s founder and CTO) 宣布docker的官方镜像要从fedora和ubuntu这种笨重的发行版迁移到轻量级的alpine linux.</p></blockquote><blockquote><p>Solomon Hykes not only announced that all Official Docker images will move to Alpine Linux but that @Nathanel Copa the creator of Alpine Linux joined the Docker team.</p></blockquote><div><img alt="Screenshot-from-2016-02-10-10-39-52-1.png" src="https://ttys3.dev/static/assets/Screenshot-from-2016-02-10-10-39-52-1-PTBFHBQH.png" width="1435" height="183"/></div><p>消息来源参考: <a href="https://news.ycombinator.com/item?id=10998667">https://news.ycombinator.com/item?id=10998667</a> <a href="https://news.ycombinator.com/item?id=11044980">https://news.ycombinator.com/item?id=11044980</a></p><p>很明显,这条消息,对于Fedora或Ubuntu来说,都是非常坏的.</p><p>当然,ubuntu马上发文对此进行了回应 <a href="https://ubuntu.com/blog/docker-alpine-ubuntu-and-you">https://ubuntu.com/blog/docker-alpine-ubuntu-and-you</a> :</p><p>回应说,<strong>你Docker家自己的默认镜像爱用啥用啥,我当然管不着。但是有几件事我得说清楚。</strong></p><p>(1) 如果单从pull下载数量来说, DockerHub上的Busybox (Alpine Linux) 已经以66M的数量打败了Ubuntu 的40M. 但是如果从用户的喜好程序(star数量)来看,ubuntu 比 alpien 是3.2K 比 499</p><p>(2) ubuntu minimal版的镜像的tar压缩包大小只有59 MB,这个才是在pull的时候需要传输的数据量,虽然这个root filesystem解压后会有188 MB大小.</p><p>(3) 由于Docker用的是overlay fs, 这个fs的魔法之处在于,base image其实你只需要pull一次,存储在磁盘上也只需要存储一次而已。</p><p>在这种情况下,alpine 的2M tar压缩包(解压之后大概5M)并没有什么优势. 然后拿命令示范了一下pull两个base image的时间,以及run 一下这两个base image里的/bin/true的时间,数据表示几乎是一样的。 (言外之意,你体积小个几十M,速度上好像没啥优势啊?) 老灯看来,执行一个/bin/true真不能说明什么. 如果真要比较这两个系统的效率,要跑benchmark, 并且还要关注cpu和ram的使用及负载情况. 这样才客观,所以,ubuntu的这个run的例子,不必太当真. 老灯没有做过对比,因此也不好下结论.</p><p>(4) 第四点就不翻译了,技术无关。吹了一下ubuntu这个公司有多牛逼,然后,反问了下,你找的那个 alpine 创始人Nathanel我并没听过,不知道他有啥能耐.</p><p>(5) 第五点差不比就是比较一下ubuntu和alpine里package的数量,ubuntu完全秒了你alpine. 然后继续宣传下自己: 就像发条一样,Ubuntu带来的是精准,效率和稳定. Like clockwork. Choice. Velocity. Stability. That’s what Ubuntu brings.</p><p>虽然老灯当前不怎么使用ubuntu(早期还是用过的)了,但是对于ubuntu家发的这个文章,老灯基本上是认同的. alpine 5M体积的卖点,真的没有那么美好. 由于容器是使用的overlay fs, 因此,base image体积的大小,其实关系不是很大. 当然,作为base image应该尽量精简,在一定的体积范围内,我们完全没有必要追求极致地小. 我们要关心的是什么?用这个base image构建我的应用,方便不方便?用这个base image,来运行我的服务方便不方便? 构建应用,主要是要考虑 发行版 软件包的数量 和 质量 以及更新维护频率了 (老实说,apline包的数量,远不及debian系或rhel系). 而稳定性,主要是rootfs 以及 底层库决定的,比如glibc 之类的. 方便性的话,主要考虑,基于这个base image的服务器daemon应用多不多,比如常见的nginx, mysql, mariadb, redis, mongodb, php-fpm 等</p><blockquote><p>只有5M的 alpine 无疑是最小的. 但是其带来的问题,有时候远远比节省的这几十M要多很多.</p></blockquote><h2 id="alpine踩坑真实案例"><a href="#alpine踩坑真实案例" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>alpine踩坑真实案例</h2><h3 id="坑1-musl-libc-和-glibc-之间的差异"><a href="#坑1-musl-libc-和-glibc-之间的差异" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>坑1. musl libc 和 glibc 之间的差异</h3><p>libc是底层库,底层的变动,可能会带来很多你平常使用glibc时不会遇到的麻烦。 musl libc 一般是用于嵌入式操作系统比较多。比如 OpenWRT 就是采用的 musl libc, 原因很简单, 这类系统,运行的硬件资源都是非常有限的,可能只有8M闪存,甚至更小的,4M闪存。使用glibc当然是不太现实。 把alpine 和 musl libc吹上天的,可能也只有docker官方了。</p><p>老灯的qBittorrent镜像,之前一直是使用alpine构建,多层构建之后的运行环境,也使用的是alpine. 然而有一天,突然有人报告说,qBittorrent在添加了某个种子之后,就挂了,再也起不来了。</p><p>于是我想,能不能在编译时把调试开启,并且启用stacktrace,这样程序挂掉了,至少咱能知道,它是怎么死的。</p><p>然而,在alpine容器里尝试编译用于调试的qBittorrent时,我遇到了一个麻烦.</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">./configure --disable-gui --enable-stacktrace --enable-debug </span><span class="code-line">Project MESSAGE: Project is built <span class="token keyword">in</span> DEBUG mode. </span><span class="code-line"><span class="token comment"># 遇到错误1</span> </span><span class="code-line">compiling base/bittorrent/private/bandwidthscheduler.cpp </span><span class="code-line">In <span class="token function">file</span> included from app/main.cpp:70: </span><span class="code-line">app/stacktrace.h:9:10: fatal error: execinfo.h: No such <span class="token function">file</span> or directory </span><span class="code-line"> <span class="token number">9</span> <span class="token operator">|</span> <span class="token comment">#include &lt;execinfo.h&gt;</span> </span><span class="code-line"> <span class="token operator">|</span> ^~~~~~~~~~~~ </span><span class="code-line">compilation terminated. </span><span class="code-line">make<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>: *** <span class="token punctuation">[</span>Makefile:2119: main.o<span class="token punctuation">]</span> Error <span class="token number">1</span> </span><span class="code-line"><span class="token comment"># 查询到包名,过了第一关</span> </span><span class="code-line">https://pkgs.alpinelinux.org/contents?file<span class="token operator">=</span>execinfo.h<span class="token operator">&amp;</span><span class="token variable assign-left">path</span><span class="token operator">=</span><span class="token operator">&amp;</span><span class="token variable assign-left">name</span><span class="token operator">=</span><span class="token operator">&amp;</span><span class="token variable assign-left">branch</span><span class="token operator">=</span>v3.11<span class="token operator">&amp;</span><span class="token variable assign-left">arch</span><span class="token operator">=</span>x86_64 </span><span class="code-line">libexecinfo-dev </span><span class="code-line"><span class="token comment"># 然而还是没用</span> </span><span class="code-line">linking qbittorrent-nox </span><span class="code-line">/usr/lib/gcc/x86_64-alpine-linux-musl/9.2.0/<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/<span class="token punctuation">..</span>/x86_64-alpine-linux-musl/bin/ld: main.o: <span class="token keyword">in</span> <span class="token keyword">function</span> <span class="token variable"><span class="token variable">`</span>print_stacktrace&#x27;: </span></span><span class="code-line"><span class="token variable">/tmp/qbittorrent/src/app/stacktrace.h:23: undefined reference to <span class="token variable">`</span></span>backtrace<span class="token string">&#x27; </span></span><span class="code-line"><span class="token string">/usr/lib/gcc/x86_64-alpine-linux-musl/9.2.0/../../../../x86_64-alpine-linux-musl/bin/ld: /tmp/qbittorrent/src/app/stacktrace.h:32: undefined reference to `backtrace_symbols&#x27;</span> </span><span class="code-line">collect2: error: ld returned <span class="token number">1</span> <span class="token builtin class-name">exit</span> status </span></code></pre></div><p>也就是说,在alpine下面,即使安装了<code>libexecinfo-dev</code>这个包,你也没法启用stacktrace, 因为它压根就没有实现<code>backtrace</code>这个函数。</p><p>我们知道,alpine的特别之处在于,它没有使用标准的linux组件和标准的glibc, 而是使用了busybox + musl libc</p><p>根据前人的一些讨论,老灯最终确认了 musl libc 是没有 backtrace 支持的:</p><p><a href="https://github.com/openalpr/openalpr/issues/566#issuecomment-34820554">https://github.com/openalpr/openalpr/issues/566#issuecomment-34820554</a></p><blockquote><p>Alpine comes with a different c lib - musl instead of the more common glibc. And as it turns out, musl does not support backtrace.</p></blockquote><p><a href="https://gitlab.alpinelinux.org/alpine/aports/issues/5079#note_23491">https://gitlab.alpinelinux.org/alpine/aports/issues/5079#note_23491</a></p><blockquote><p>Przemysław Pawełczyk @przemoc · 4 years ago RocksDB uses backtrace() and backtrace_symbols() functions and their declarations are usually put in execinfo.h, which comes with libc headers. Gnulib provides only stubs (doing nothing) on platforms lacking it. musl libc, which is used in Alpine Linux, does not provide such functions, though. Please read <a href="http://thread.gmane.org/gmane.linux.lib.musl.general/7356/focus=7369">http://thread.gmane.org/gmane.linux.lib.musl.general/7356/focus=7369</a> for more information and replies to Rich Felker mail for alternative workaround, which may be easier to go with, because libunwind is already in testing repository. (from redmine: written on 2016-02-28)</p></blockquote><p>没错,这些issue都是四五年前的了,至今无解.</p><h3 id="坑2-少数派的麻烦"><a href="#坑2-少数派的麻烦" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>坑2. 少数派的麻烦</h3><p>通常大说libc, 基本上是指的glibc, 问题是,很多库的作者在写库的时候,可能从来就没考虑过musl libc这种东西。</p><p>有一个比较典型的例子是 docker 官方发布的 PHP 镜像。 <a href="https://github.com/docker-library/php/issues/240">https://github.com/docker-library/php/issues/240</a></p><p>这个镜像有什么问题呢? 最常用的 <code>iconv</code> 函数不能正常工作。这个问题在任何基于GNU LIBC的Linux发行版上都是不可能存在的。</p><p>老灯也不清楚,alpine上面的musl libc 在处理字符转换时是怎样的一个实现,很可能它压根就没有实现。</p><p>反正,最终的解决办法还是:只能从edge仓库安装 GNU libiconv (这是何苦呢?放着 GNU libc不用,完了 musl libc下面的东西搞不定,还得找GNU借内裤(lib))</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">RUN apk <span class="token function">add</span> --no-cache <span class="token variable parameter">--repository</span> http://dl-3.alpinelinux.org/alpine/edge/testing gnu-libiconv </span><span class="code-line">ENV LD_PRELOAD /usr/lib/preloadable_libiconv.so php </span></code></pre></div><p>没错,这个方法解决了问题,但是只能算是一个 workaround 或者说 hacking.</p><p>除了我所遇到的问题,还有其它人也遇到了:</p><ol><li>python相关的: 使用Alpine构建 Python docker容器速度慢了50倍</li></ol><p><a href="https://pythonspeed.com/articles/base-image-python-docker-images/">https://pythonspeed.com/articles/base-image-python-docker-images/</a></p><p>Using Alpine can make Python Docker builds 50× slower by Itamar Turner-Trauring Last updated 10 Feb 2020, originally created 29 Jan 2020 <a href="https://pythonspeed.com/articles/alpine-docker-python/">https://pythonspeed.com/articles/alpine-docker-python/</a></p><ol start="2"><li><p>elastic: 从alpine base image切换到CentOS 7 <a href="https://github.com/elastic/elasticsearch-docker/issues/44">https://github.com/elastic/elasticsearch-docker/issues/44</a> New Common Docker Base OS: CentOS 7 <a href="https://www.elastic.co/blog/docker-base-centos7">https://www.elastic.co/blog/docker-base-centos7</a></p></li><li><p>small is not all that matters <a href="http://crunchtools.com/comparison-linux-container-images/">http://crunchtools.com/comparison-linux-container-images/</a> Which C library, package format and core utilities are used, may be more important than you think. Most distributions use the same tools, but Alpine Linux has special versions of all of these, for the express purpose of a making a small distribution. But, small is not all that matters.</p></li></ol><p>Changing core libraries and utilities can have a profound effect on what software will compile and run. It can also affect performance, security and cause discreet failure with the large and complex software stacks that are common today. Distributions have tried moving to smaller C libraries, and eventually moved back to glibc. The Debian Project and Elastic are two examples. Glibc just works, and it works everywhere, and it has had a profound amount of testing and usage over the years. It’s a similar story with GCC – tons of testing and automation.</p><ol start="4"><li><p>Debian is switching (back) to GLIBC Five years ago Debian and most derivatives switched from the standard GNU C Library (GLIBC) to the Embedded GLIBC (EGLIBC). Debian is now about to take the reverse way switching back to GLIBC, as EGLIBC is now a dead project, the last release being the 2.19 one. At the time of writing the glibc package has been uploaded to experimental and sits in the NEW queue. <a href="https://blog.aurel32.net/175">https://blog.aurel32.net/175</a></p></li><li><p>DNS 和 其它不兼容问题</p></li></ol><p><a href="https://github.com/gliderlabs/docker-alpine/blob/master/docs/caveats.md#dns">https://github.com/gliderlabs/docker-alpine/blob/master/docs/caveats.md#dns</a></p><p>DNS</p><p>One common issue you may find is with DNS. musl libc does not use domain or search directives in the /etc/resolv.conf file. For example, if you started your Docker daemon with --dns-search=service.consul, and then tried to resolve consul from within an Alpine Linux container, it would fail as the name consul.service.consul would not be tried. You will need to work around this by using fully qualified names.</p><p>Another difference is parallel querying of name servers. This can be problematic if your first name server has a different DNS view (such as service discovery through DNS). For example, if you started your Docker daemon with --dns=172.17.42.1 --dns=10.0.2.15 where 172.17.42.1 is a local DNS server to resolve name for service discovery and 10.0.2.15 is for external DNS resolving, you wouldn&#x27;t be able to guarantee that 172.17.42.1 will always be queried first. There will be sporadic failures.</p><p>In both of these cases, it can help to run a local caching DNS server such as dnsmasq, that can be used for both caching and search path routing. Running dnsmasq with --server /consul/10.0.0.1 would forward queries for the .consul to 10.0.0.1. Incompatible Binaries</p><p>While there are binaries that will run on musl libc without needing to be recompiled, you will likely encounter binaries and applications that rely on specific glibc functionality that will fail to start up. An example of this would be Oracle Java which relies on specific symbols only found in glibc. You can often use ldd to determine the exact symbol:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token comment"># ldd bin/java</span> </span><span class="code-line"> /lib64/ld-linux-x86-64.so.2 <span class="token punctuation">(</span>0x7f542ebb5000<span class="token punctuation">)</span> </span><span class="code-line"> libpthread.so.0 <span class="token operator">=</span><span class="token operator">&gt;</span> /lib64/ld-linux-x86-64.so.2 <span class="token punctuation">(</span>0x7f542ebb5000<span class="token punctuation">)</span> </span><span class="code-line"> libjli.so <span class="token operator">=</span><span class="token operator">&gt;</span> bin/<span class="token punctuation">..</span>/lib/amd64/jli/libjli.so <span class="token punctuation">(</span>0x7f542e9a0000<span class="token punctuation">)</span> </span><span class="code-line"> libdl.so.2 <span class="token operator">=</span><span class="token operator">&gt;</span> /lib64/ld-linux-x86-64.so.2 <span class="token punctuation">(</span>0x7f542ebb5000<span class="token punctuation">)</span> </span><span class="code-line"> libc.so.6 <span class="token operator">=</span><span class="token operator">&gt;</span> /lib64/ld-linux-x86-64.so.2 <span class="token punctuation">(</span>0x7f542ebb5000<span class="token punctuation">)</span> </span><span class="code-line">Error relocating bin/<span class="token punctuation">..</span>/lib/amd64/jli/libjli.so: __rawmemchr: symbol not found </span></code></pre></div><p>In this case, the upstream would need to remove the support for this offending symbol or have the ability to compile the software natively on musl libc. Be sure to check the Alpine Linux package index to see if a suitable replacement package already exists.</p><h2 id="alpine的体积优势可以忽略"><a href="#alpine的体积优势可以忽略" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>alpine的体积优势可以忽略</h2><p>那么,debian stable呢? slim版(去除了man等一些不必要的东西)压缩后的体积<strong>也才26MB</strong>. 比如 <a href="https://hub.docker.com/layers/debian/library/debian/buster-slim/images/sha256-55d08af3a56d2adc81562f5b811b239e773df6037d4f7e41458ded660416b0cc?context=explore">https://hub.docker.com/layers/debian/library/debian/buster-slim/images/sha256-55d08af3a56d2adc81562f5b811b239e773df6037d4f7e41458ded660416b0cc?context=explore</a> Size 26.46 MB 注:当前(2020年3月26日)stable 版本为 Debian 10 (&quot;buster&quot;)</p><p>然后我们看下目前alpine最新稳定版 3.11 <a href="https://hub.docker.com/layers/alpine/library/alpine/3.11/images/sha256-04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c?context=explore">https://hub.docker.com/layers/alpine/library/alpine/3.11/images/sha256-04d04970e33c492fa411b508455d02a85978492db0403b8a714f365432c04f1c?context=explore</a> Size 2.69 MB 没错,压缩后才2.69MB, 确实够小. 但是debian buster slim 多出的24MB 就很多么?以当前机械硬盘动不动就是上TB的容量来说,完全没啥区别吧. 即使是SSD, 现在也基本上是往480GB 以上的买了. 另一方面, 由于容器(比如podman, docker) 都是用的overlay fs, 镜像是分层的,同一个 base image 是可以在各个镜像之间共享的. 多个镜像并不会占用多倍的体积. 所以,对于base image来说,体积真的是不需要考虑的东西.</p><p>那么要考虑什么? package的更新维护及运行效率和资源占用,尤其是针对CPU比较弱的机器(比如arm64设备)</p><h2 id="docker官方也不是一味地使用alpine"><a href="#docker官方也不是一味地使用alpine" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>docker官方也不是一味地使用alpine</h2><p>我们可以看看docker官方发布的镜像偏爱什么发行版?(只考虑linux系统的)</p><p>golang: debian 9 stretch 和 debian 10 buster 还有alpine 3.10和 3.11 <strong>注意: 当前的golnag默认镜像,是基于debian的,并不是alpine!</strong> <code>docker run --rm -ti golang:1.14 cat /etc/os-release</code> 便可知。 <a href="https://hub.docker.com/_/golang">https://hub.docker.com/_/golang</a></p><p>rust: debian 9 stretch 和 debian 10 buster 及各自的slim版,还有alpine 3.10和 3.11 <a href="https://hub.docker.com/_/rust">https://hub.docker.com/_/rust</a></p><p>我们看看python: <a href="https://hub.docker.com/_/python">https://hub.docker.com/_/python</a> 基本上是debian 9 stretch 和 debian 10 buster 还有alpine 3.10和 3.11,都是这两个发行版当前的主流版本.</p><p>java: debian 9 stretch 和 debian 10 buster 及各自的slim版,还有alpine 3.10和 3.11 <a href="https://hub.docker.com/_/openjdk">https://hub.docker.com/_/openjdk</a> <a href="https://github.com/docker-library/docs/blob/master/openjdk/README.md#supported-tags-and-respective-dockerfile-links">https://github.com/docker-library/docs/blob/master/openjdk/README.md#supported-tags-and-respective-dockerfile-links</a></p><p>php: debian 9 stretch 和 debian 10 buster 还有alpine 3.10和 3.11 <a href="https://github.com/docker-library/docs/blob/master/php/README.md#supported-tags-and-respective-dockerfile-links">https://github.com/docker-library/docs/blob/master/php/README.md#supported-tags-and-respective-dockerfile-links</a></p><p>node.js: debian 9 stretch 和 debian 10 buster 及各自的slim版,还有alpine 3.10和 3.11 <a href="https://hub.docker.com/_/node">https://hub.docker.com/_/node</a></p><p>nginx: 基本上是alpine <a href="https://hub.docker.com/_/nginx">https://hub.docker.com/_/nginx</a></p><p>apache httpd: 基本上是alpine <a href="https://hub.docker.com/_/httpd">https://hub.docker.com/_/httpd</a></p><p>jenkins: alpine <a href="https://hub.docker.com/_/jenkins">https://hub.docker.com/_/jenkins</a> phpmyadmin: alpine <a href="https://hub.docker.com/r/phpmyadmin/phpmyadmin/dockerfile">https://hub.docker.com/r/phpmyadmin/phpmyadmin/dockerfile</a></p><p>mysql数据库: debian:buster-slim <a href="https://github.com/docker-library/mysql/blob/d284e15821ac64b6eda1b146775bf4b6f4844077/8.0/Dockerfile">https://github.com/docker-library/mysql/blob/d284e15821ac64b6eda1b146775bf4b6f4844077/8.0/Dockerfile</a></p><p>mariadb: ubuntu bionic <a href="https://hub.docker.com/_/mariadb">https://hub.docker.com/_/mariadb</a></p><p>redis: debian buster 和 apline 3.11 <a href="https://hub.docker.com/_/redis">https://hub.docker.com/_/redis</a></p><p>mongo: <a href="https://hub.docker.com/_/mongo">https://hub.docker.com/_/mongo</a> ubuntu xenial 和 bionic</p><p>从上面这些可以看出什么?虽然docker极力想要把base image从ubuntu迁移到alpine, 但是考虑到用户的选择问题,还是做出了妥协, 既然不想再用fedora和ubuntu了,那么就用一下debian吧.</p><h2 id="老灯推荐"><a href="#老灯推荐" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>老灯推荐</h2><p>无论是构建应用,还是运行应用,老灯觉得以下几个镜像都比较适合生产环境:</p><p>debian-slim <a href="https://hub.docker.com/_/debian">https://hub.docker.com/_/debian</a></p><div class="relative"><pre><code class="language-docker code-highlight"><span class="code-line"><span class="token instruction"><span class="token keyword">FROM</span> debian:buster-slim</span> </span></code></pre></div><p>ubuntu <a href="https://hub.docker.com/_/ubuntu">https://hub.docker.com/_/ubuntu</a></p><div class="relative"><pre><code class="language-docker code-highlight"><span class="code-line"><span class="token instruction"><span class="token keyword">FROM</span> ubuntu:18.04</span> </span></code></pre></div><div class="relative"><pre><code class="language-docker code-highlight"><span class="code-line"><span class="token instruction"><span class="token keyword">FROM</span> ubuntu:20.04</span> </span></code></pre></div><p>centos <a href="https://hub.docker.com/_/centos">https://hub.docker.com/_/centos</a></p><div class="relative"><pre><code class="language-docker code-highlight"><span class="code-line"><span class="token instruction"><span class="token keyword">FROM</span> centos:8.2.2004</span> </span></code></pre></div><p>对于日常使用来说,fedora也可以:</p><p>fedora <a href="https://hub.docker.com/_/fedora">https://hub.docker.com/_/fedora</a></p><div class="relative"><pre><code class="language-docker code-highlight"><span class="code-line"><span class="token instruction"><span class="token keyword">FROM</span> fedora:32</span> </span></code></pre></div><p>Fedora 官方 registry 还有mininal版 <a href="https://registry.fedoraproject.org/">https://registry.fedoraproject.org/</a></p><div class="relative"><pre><code class="language-docker code-highlight"><span class="code-line"><span class="token instruction"><span class="token keyword">FROM</span> registry.fedoraproject.org/fedora-minimal:latest</span> </span></code></pre></div><p>任何时候在生产环境都不要上alpine, 如果你真的差这20M,别用docker了,直接编译了加个systemd跑服务吧</p> Sun, 12 Jul 2020 17:41:00 GMT ttyS3 alpinedockerwtf https://ttys3.dev/blog/Fedora32和Docker的那些事儿 Fedora32和Docker的那些事儿 https://ttys3.dev/blog/Fedora32和Docker的那些事儿 <h2 id="moby-vs-docker-ce"><a href="#moby-vs-docker-ce" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Moby vs Docker CE</h2><p>Fedora 32 都发布好久了,然而 Docker 官方迟迟没有发布适用于 Fedora 32 的 Docker CE rpm包。</p><p>当然,肯定不只老灯一个人在关注这个问题, 这不, docker官方repo里有人提issue了:</p><p><a href="https://github.com/docker/for-linux/issues/955">Please provide repo for docker-ce on Fedora 32 #955</a></p><p>然后 Fedora 官方博客写了一篇名叫《<a href="https://fedoramagazine.org/docker-and-fedora-32/">如何在Fedora 32上安装Docker</a>》的教程, 然后老灯一看,这哪是安装什么Docker, 这是安装 Moby 啊。</p><p>很久以前, Docker 还是 Docker, 直到有一天, Docker 公司将开源项目重命名为了 Moby, 现在大家用的免费的 Docker 全称应该叫 Docker CE. 对于这段往事感兴趣的童鞋可自行施展Google-Fu, 老灯这里就不多说了。</p><p>那么,Moby 和 Docker 的区别是什么?</p><p>根据 Docker 官方的说明( <a href="https://www.docker.com/blog/introducing-the-moby-project/">https://www.docker.com/blog/introducing-the-moby-project/</a> ):</p><blockquote><p><strong>Moby</strong> is designed for <strong>system builders</strong>, who want to build <strong>their own container based systems</strong>, <strong>not for application developers, who can use Docker or other container platforms.</strong> Participants in the Moby project can choose from the library of components derived from Docker or they can elect to “bring your own components” (BYOC) packaged as containers with the option to mix and match among all of the components to create a customized container system.</p></blockquote><p>另外一个文章也有类似的说明 <a href="https://www.cio.com/article/3191344/why-docker-created-the-moby-project.html">https://www.cio.com/article/3191344/why-docker-created-the-moby-project.html</a></p><blockquote><p>“Essentially, Docker is building a LEGO club for the ecosystem with Docker at the center of it,” said Docker&#x27;s VP of marketing David Messina.</p><p>The Moby Project will become a place where experimental, bleeding edge features of Docker will take shape. It will be the place where you will see the next release of Docker. <strong>The Moby Project is to Docker what Fedora is to Red Hat Enterprise Linux</strong></p></blockquote><p>因此,这二者的定位是完全不同的。Moby 是用来给你打造你自己的 Docker 的,而不是给应用开发者使用。与其凑合着安装一个不知道在什么情况下会有坑的 Moby, 不如安装 Docker 官方 Fedora 31 仓库里的 Docker.</p><h2 id="如何在-fedora-32-下安装-docker-ce"><a href="#如何在-fedora-32-下安装-docker-ce" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何在 Fedora 32 下安装 Docker CE</h2><p>安装过程很简单,也很顺利,老灯在此也顺便说一下。</p><p>主要参考 <a href="https://docs.docker.com/engine/install/fedora/">https://docs.docker.com/engine/install/fedora/</a></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token variable parameter">-y</span> <span class="token function">install</span> dnf-plugins-core </span><span class="code-line"><span class="token function">sudo</span> dnf config-manager <span class="token punctuation">\</span> </span><span class="code-line"> --add-repo <span class="token punctuation">\</span> </span><span class="code-line"> https://download.docker.com/linux/fedora/docker-ce.repo </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 然后,我们简单地把 32 替换成 31 即可(因为Docker还没有发布f32的rpm)</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">sed</span> <span class="token variable parameter">-i</span> <span class="token string">&#x27;s/$releasever/31/g&#x27;</span> <span class="token builtin class-name">cd</span> /etc/yum.repos.d/docker-ce.repo </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 安装</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> docker-ce docker-ce-cli containerd.io </span></code></pre></div><p>光安装好了还不行,因为 F32 默认启用了 <code>CGroup v2</code>, 而当前版本的 Docker CE 还只支持 v1, 因此,我们得开倒车.</p><blockquote><p>For Fedora 31 and higher, you need to enable the <a href="https://fedoraproject.org/wiki/Common_F31_bugs#Docker_package_no_longer_available_and_will_not_run_by_default_.28due_to_switch_to_cgroups_v2.29">backward compatibility for Cgroups</a></p></blockquote><p>编辑 <code>/etc/default/grub</code> 文件, <code>GRUB_CMDLINE_LINUX</code> 增加参数:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token attr-name key">systemd.unified_cgroup_hierarchy</span><span class="token punctuation">=</span><span class="token attr-value value">0</span> </span></code></pre></div><p>更新grub配置:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> grub2-mkconfig <span class="token variable parameter">-o</span> /etc/grub2-efi.cfg </span></code></pre></div><p>把自己加到 docker 用户组(针对日常开发情况):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">usermod</span> <span class="token variable parameter">-aG</span> <span class="token function">docker</span> your-user </span></code></pre></div><p>然后重启系统。</p><p>启用服务:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> systemctl <span class="token builtin class-name">enable</span> <span class="token variable parameter">--now</span> <span class="token function">docker</span> </span></code></pre></div><p>测试:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">docker</span> run hello-world </span></code></pre></div><p>目前来说工作良好。</p><p>另外, <code>runc</code> 的 <a href="https://github.com/opencontainers/runc/issues/2315">cgroupv2 support meta issue #2315</a> 也已经完成得差不多了</p><p><code>containerd</code> 那边还没有搞定 <a href="https://github.com/containerd/containerd/issues/3726">cgroups v2 Support #3726</a></p><p>RPM spec for Fedora 32 is here: <a href="https://github.com/docker/docker-ce-packaging/tree/master/rpm">https://github.com/docker/docker-ce-packaging/tree/master/rpm</a></p><p>相信再过一段时间, 等 cgroupv2 的支持问题解决了, Fedora 32 将被 Docker 支持。</p><h2 id="如何设置代理"><a href="#如何设置代理" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何设置代理</h2><p>主要是参考 <a href="https://docs.docker.com/config/daemon/systemd/#httphttps-proxy">https://docs.docker.com/config/daemon/systemd/#httphttps-proxy</a></p><p>由于 Docker 的 cli 只是负责给 <code>dockerd</code> 发命令,因此实际上我们要配置 <code>dockerd</code> 使用代理。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">mkdir</span> <span class="token variable parameter">-p</span> /etc/systemd/system/docker.service.d </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">touch</span> /etc/systemd/system/docker.service.d/http-proxy.conf </span></code></pre></div><p>老灯本地有 http 代理, 因此配置 <code>/etc/systemd/system/docker.service.d/http-proxy.conf</code> 内容如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Service</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Environment</span><span class="token punctuation">=</span><span class="token attr-value value">&quot;<span class="token inner-value">HTTP_PROXY=http://192.168.8.100:7070</span>&quot;</span> </span><span class="code-line"><span class="token attr-name key">Environment</span><span class="token punctuation">=</span><span class="token attr-value value">&quot;<span class="token inner-value">NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16</span>&quot;</span> </span></code></pre></div><p>然后重启 dockerd</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> systemctl daemon-reload </span><span class="code-line"><span class="token function">sudo</span> systemctl restart <span class="token function">docker</span> </span></code></pre></div><p>检查下配置是否生效:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> systemctl show <span class="token variable parameter">--property</span><span class="token operator">=</span>Environment <span class="token function">docker</span> </span><span class="code-line"><span class="token variable assign-left">Environment</span><span class="token operator">=</span>HTTP_PROXY<span class="token operator">=</span>http://192.168.8.100:7070 <span class="token variable assign-left">NO_PROXY</span><span class="token operator">=</span>localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 </span></code></pre></div><h2 id="如何卸载"><a href="#如何卸载" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何卸载</h2><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf remove docker-ce docker-ce-cli containerd.io </span></code></pre></div> Thu, 09 Jul 2020 17:44:55 GMT ttyS3 FedoraDockerCgroupV2 https://ttys3.dev/blog/mirror Mirror https://ttys3.dev/blog/mirror <hr/><h1 id="老灯常用镜像源"><a href="#老灯常用镜像源" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>老灯常用镜像源</h1><h2 id="linux-镜像源"><a href="#linux-镜像源" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Linux 镜像源</h2><ul><li><p>清华大学开源软件镜像站 <a href="https://mirrors.tuna.tsinghua.edu.cn/">https://mirrors.tuna.tsinghua.edu.cn/</a></p></li><li><p>中国科学技术大学开源软件镜像 <a href="https://mirrors.ustc.edu.cn/">https://mirrors.ustc.edu.cn/</a></p></li><li><p>上海交通大学 Linux 用户组 镜像源服务 <a href="https://mirrors.sjtug.sjtu.edu.cn/">https://mirrors.sjtug.sjtu.edu.cn/</a></p></li></ul><blockquote><p>tuna 和 ustc 的源比较全面, 而 sjtug 的源相对来说比较少,比如 RHEL 系常用的 <code>epel</code> 和 <code>rpmfusion</code> 都没有。</p></blockquote><h3 id="archlinux-源"><a href="#archlinux-源" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>ArchLinux 源</h3><p><code>/etc/pacman.d/mirrorlist</code></p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token key attr-name">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch</span> </span><span class="code-line"><span class="token key attr-name">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirror.sjtu.edu.cn/archlinux/$repo/os/$arch</span> </span></code></pre></div><p>ArchLinux CN 源 编辑 <code>/etc/pacman.conf</code> 在最后加上:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">archlinuxcn</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token key attr-name">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.ustc.edu.cn/archlinuxcn/$repo/os/$arch</span> </span><span class="code-line"><span class="token key attr-name">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.sjtug.sjtu.edu.cn/archlinux-cn/$arch</span> </span></code></pre></div><p>注意:sjtug 中间有一个<code>-</code>, 而 ustc 则没有,直接是 <code>archlinuxcn</code></p><h3 id="fedora-源使用方法适用于fedora-32之后"><a href="#fedora-源使用方法适用于fedora-32之后" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Fedora 源使用方法(适用于Fedora 32之后)</h3><p>注意 Fedora 32 之后的将默认的<code>http://download.fedoraproject.org/pub/fedora/linux</code> 变成了 <code>http://download.example/pub/fedora/linux</code></p><p>sjtug</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">sed</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^metalink=|#metalink=|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^#baseurl=http://download.example/pub/fedora/linux|baseurl=https://mirrors.sjtug.sjtu.edu.cn/fedora/linux|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-i.bak</span> <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-modular.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-updates.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-updates-modular.repo </span></code></pre></div><p>repo与url对应关系:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">fedora <span class="token operator">-</span><span class="token operator">&gt;</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>fedora<span class="token operator">/</span>linux<span class="token operator">/</span>releases<span class="token operator">/</span><span class="token number">32</span><span class="token operator">/</span><span class="token maybe-class-name">Everything</span><span class="token operator">/</span>x86_64<span class="token operator">/</span> </span><span class="code-line">fedora<span class="token operator">-</span>modular <span class="token operator">-</span><span class="token operator">&gt;</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>fedora<span class="token operator">/</span>linux<span class="token operator">/</span>releases<span class="token operator">/</span><span class="token number">32</span><span class="token operator">/</span><span class="token maybe-class-name">Modular</span><span class="token operator">/</span>x86_64<span class="token operator">/</span> </span><span class="code-line"> </span><span class="code-line">fedora<span class="token operator">-</span>updates <span class="token operator">-</span><span class="token operator">&gt;</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>fedora<span class="token operator">/</span>linux<span class="token operator">/</span>updates<span class="token operator">/</span><span class="token number">32</span><span class="token operator">/</span><span class="token maybe-class-name">Everything</span><span class="token operator">/</span>x86_64<span class="token operator">/</span> </span><span class="code-line">fedora<span class="token operator">-</span>updates<span class="token operator">-</span>modular <span class="token operator">-</span><span class="token operator">&gt;</span> https<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>mirrors<span class="token punctuation">.</span><span class="token property-access">sjtug</span><span class="token punctuation">.</span><span class="token property-access">sjtu</span><span class="token punctuation">.</span><span class="token property-access">edu</span><span class="token punctuation">.</span><span class="token property-access">cn</span><span class="token operator">/</span>fedora<span class="token operator">/</span>linux<span class="token operator">/</span>updates<span class="token operator">/</span><span class="token number">32</span><span class="token operator">/</span><span class="token maybe-class-name">Modular</span><span class="token operator">/</span>x86_64<span class="token operator">/</span> </span></code></pre></div><blockquote><p>注意: ustc 源 和 tuna 源 的url里都没有<code>linux</code>这层目录</p></blockquote><p>ustc源:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">sed</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^metalink=|#metalink=|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^#baseurl=http://download.example/pub/fedora/linux|baseurl=https://mirrors.ustc.edu.cn/fedora|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-i.bak</span> <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-modular.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-updates.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-updates-modular.repo </span></code></pre></div><p>tuna源:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">sed</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^metalink=|#metalink=|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^#baseurl=http://download.example/pub/fedora/linux|baseurl=https://mirrors.tuna.tsinghua.edu.cn/fedora|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-i.bak</span> <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-modular.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-updates.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-updates-modular.repo </span></code></pre></div><p>rpmfusion源:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">http://download1.rpmfusion.org/ 替换为 </span><span class="code-line"> </span><span class="code-line">https://mirror.sjtu.edu.cn/rpmfusion/ </span><span class="code-line"> </span><span class="code-line">或 </span><span class="code-line"> </span><span class="code-line">https://mirrors.ustc.edu.cn/rpmfusion/ </span><span class="code-line"> </span><span class="code-line">或 </span><span class="code-line"> </span><span class="code-line">https://mirrors.tuna.tsinghua.edu.cn/rpmfusion/ </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">sed</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^metalink=|#metalink=|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^#baseurl=http://download1.rpmfusion.org/|baseurl=https://mirrors.ustc.edu.cn/rpmfusion/|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-i.bak</span> <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/rpmfusion-free.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/rpmfusion-free-updates.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/rpmfusion-free-updates-testing.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/rpmfusion-nonfree.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/rpmfusion-nonfree-steam.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/rpmfusion-nonfree-updates.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/rpmfusion-nonfree-updates-testing.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/rpmfusion-nonfree-nvidia-driver.repo </span></code></pre></div><p>misc:</p><p>sjtug 有提供 Google Fonts 反代, 使用方式举例: <code>https://fonts.googleapis.com/css?family=Roboto</code> 换成 <code>https://google-fonts.mirrors.sjtug.sjtu.edu.cn/css?family=Roboto</code> 即可</p><p>ustc 有提供golang下载: <a href="https://mirrors.ustc.edu.cn/golang/">https://mirrors.ustc.edu.cn/golang/</a></p><hr/><h2 id="docker-registry-反代"><a href="#docker-registry-反代" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>docker-registry 反代</h2><p>2021-01-07 新增加 <a href="https://mirrors.nwafu.edu.cn/help/reverse-proxy/dockerhub/">nwafu dockerhub反代</a></p><h3 id="docker-配置"><a href="#docker-配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>docker 配置</h3><p>编辑 <code>/etc/docker/daemon.json</code>, 增加<code>registry-mirrors</code>配置:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;registry-mirrors&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&quot;https://docker.mirrors.sjtug.sjtu.edu.cn&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;https://dockerhub.mirrors.nwafu.edu.cn&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&quot;https://hub-mirror.c.163.com&quot;</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><h3 id="podman-配置"><a href="#podman-配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>podman 配置</h3><p>备份原配置 <code>/etc/containers/registries.conf</code>, 修改内容为:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token key property">unqualified-search-registries</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&#x27;docker.io&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&#x27;registry.access.redhat.com&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&#x27;quay.io&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&#x27;registry.fedoraproject.org&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&#x27;registry.centos.org&#x27;</span> </span><span class="code-line"><span class="token punctuation">]</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token class-name table">registry</span><span class="token punctuation">]</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">prefix</span> <span class="token punctuation">=</span> <span class="token string">&quot;docker.io&quot;</span> </span><span class="code-line"><span class="token key property">insecure</span> <span class="token punctuation">=</span> <span class="token boolean">false</span> </span><span class="code-line"><span class="token key property">blocked</span> <span class="token punctuation">=</span> <span class="token boolean">false</span> </span><span class="code-line"><span class="token key property">location</span> <span class="token punctuation">=</span> <span class="token string">&quot;docker.mirrors.sjtug.sjtu.edu.cn&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token class-name table">registry</span><span class="token punctuation">]</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">prefix</span> <span class="token punctuation">=</span> <span class="token string">&quot;docker.io&quot;</span> </span><span class="code-line"><span class="token key property">location</span> <span class="token punctuation">=</span> <span class="token string">&quot;dockerhub.mirrors.nwafu.edu.cn&quot;</span> </span></code></pre></div><blockquote><p>注意:曾经最好用的azk8s镜像<code>dockerhub.azk8s.cn</code>已经不再对外开放</p></blockquote><p>sjtug docker registry 测试结果: it works!</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">docker</span> pull docker.mirrors.sjtug.sjtu.edu.cn/library/busybox </span><span class="code-line">Using default tag: latest </span><span class="code-line">latest: Pulling from library/busybox </span><span class="code-line">91f30d776fb2: Pull complete </span><span class="code-line">Digest: sha256:9ddee63a712cea977267342e8750ecbc60d3aab25f04ceacfa795e6fce341793 </span><span class="code-line">Status: Downloaded newer image <span class="token keyword">for</span> docker.mirrors.sjtug.sjtu.edu.cn/library/busybox:latest </span><span class="code-line">docker.mirrors.sjtug.sjtu.edu.cn/library/busybox:latest </span></code></pre></div><p>经测试, utsc 的docker反代实际上是重定向到 <code>https://hub-mirror.c.163.com</code>:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">curl</span> <span class="token variable parameter">-I</span> https://docker.mirrors.ustc.edu.cn </span><span class="code-line">HTTP/1.1 <span class="token number">200</span> Connection established </span><span class="code-line"> </span><span class="code-line">HTTP/2 <span class="token number">302</span> </span><span class="code-line">server: openresty </span><span class="code-line">date: Thu, 09 Jul <span class="token number">2020</span> <span class="token number">16</span>:49:10 GMT </span><span class="code-line">content-type: text/html </span><span class="code-line">content-length: <span class="token number">142</span> </span><span class="code-line">location: https://hub-mirror.c.163.com/ </span></code></pre></div><p>163 docker registry 测试结果: it works!</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">docker</span> pull hub-mirror.c.163.com/library/busybox </span><span class="code-line">Using default tag: latest </span><span class="code-line">latest: Pulling from library/busybox </span><span class="code-line">Digest: sha256:9ddee63a712cea977267342e8750ecbc60d3aab25f04ceacfa795e6fce341793 </span><span class="code-line">Status: Downloaded newer image <span class="token keyword">for</span> hub-mirror.c.163.com/library/busybox:latest </span><span class="code-line">hub-mirror.c.163.com/library/busybox:latest </span></code></pre></div><p>七牛镜像没有通过测试:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">docker</span> pull reg-mirror.qiniu.com/library/busybox </span><span class="code-line">Using default tag: latest </span><span class="code-line">Error response from daemon: manifest <span class="token keyword">for</span> reg-mirror.qiniu.com/library/busybox:latest not found: manifest unknown: manifest unknown </span></code></pre></div><hr/><h2 id="golang-goproxy-反代"><a href="#golang-goproxy-反代" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Golang GOPROXY 反代</h2><p><a href="https://golang.google.cn/dl/">https://golang.google.cn/dl/</a></p><p>Go 1.13 或以上版本 (推荐)</p><p>打开终端执行一次以下命令即搞定:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">go <span class="token function">env</span> <span class="token variable parameter">-w</span> <span class="token variable assign-left">GO111MODULE</span><span class="token operator">=</span>on </span><span class="code-line">go <span class="token function">env</span> <span class="token variable parameter">-w</span> <span class="token variable assign-left">GOPROXY</span><span class="token operator">=</span>https://goproxy.cn,direct </span></code></pre></div><p>或者使用老方式:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">GO111MODULE</span><span class="token operator">=</span>on </span><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">GOPROXY</span><span class="token operator">=</span>https://goproxy.cn </span></code></pre></div><p>官方文档: <a href="https://goproxy.cn/">https://goproxy.cn/</a></p><h2 id="rust-反代"><a href="#rust-反代" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Rust 反代</h2><ul><li>环境变量 <code>RUSTUP_DIST_SERVER</code> 用于更新 toolchain</li><li>环境变量 <code>RUSTUP_UPDATE_ROOT</code> 用于更新 rustup</li><li>配置<code>crates-io</code>镜像则需要修改<code>~/.cargo/config</code>文件</li></ul><h3 id="bytedance-rsproxycn"><a href="#bytedance-rsproxycn" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Bytedance RsProxy.cn</h3><p>RsProxy.cn 目前已支持 <a href="https://doc.rust-lang.org/cargo/reference/registries.html#registry-protocols">sparse 协议</a></p><blockquote><p>The sparse protocol fetches individual metadata files using plain HTTP requests. Since Cargo only downloads the metadata for relevant crates, the sparse protocol can save significant time and bandwidth.</p></blockquote><p><code>~/.cargo/config</code>:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source.crates-io</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">replace-with</span> <span class="token punctuation">=</span> <span class="token string">&#x27;rsproxy-sparse&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source.rsproxy-sparse</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">registry</span> <span class="token punctuation">=</span> <span class="token string">&quot;sparse+https://rsproxy.cn/index/&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">registries.rsproxy</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">index</span> <span class="token punctuation">=</span> <span class="token string">&quot;https://rsproxy.cn/crates.io-index&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">net</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">git-fetch-with-cli</span> <span class="token punctuation">=</span> <span class="token boolean">true</span> </span></code></pre></div><p>Rustup Mirror</p><p><code>~/.zshrc</code> or <code>~/.bashrc</code>:</p><p>这个也最好加上:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">CARGO_UNSTABLE_SPARSE_REGISTRY</span><span class="token operator">=</span>true </span><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">CARGO_NET_GIT_FETCH_WITH_CLI</span><span class="token operator">=</span>true </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">RUSTUP_DIST_SERVER</span><span class="token operator">=</span><span class="token string">&quot;https://rsproxy.cn&quot;</span> </span><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">RUSTUP_UPDATE_ROOT</span><span class="token operator">=</span><span class="token string">&quot;https://rsproxy.cn/rustup&quot;</span> </span></code></pre></div><h3 id="sjtug"><a href="#sjtug" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>sjtug</h3><p>rust-static储存了rust的工具链及rustup本身的镜像。</p><p>使用方法:安装rustup,将以下环境变量加入<code>~/.bashrc</code>或类似文件中:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># https://mirrors.sjtug.sjtu.edu.cn/docs/rust-static</span> </span><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">RUSTUP_DIST_SERVER</span><span class="token operator">=</span>https://mirror.sjtu.edu.cn/rust-static </span><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">RUSTUP_UPDATE_ROOT</span><span class="token operator">=</span>https://mirror.sjtu.edu.cn/rust-static/rustup </span></code></pre></div><p>crates.io</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line">编辑 ~/<span class="token punctuation">.</span>cargo/config </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source</span><span class="token punctuation">]</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source.sjtu</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">registry</span> <span class="token punctuation">=</span> <span class="token string">&quot;https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index/&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source.crates-io</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">replace-with</span> <span class="token punctuation">=</span> <span class="token string">&quot;sjtu&quot;</span> </span></code></pre></div><h3 id="ustc"><a href="#ustc" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>ustc</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">RUSTUP_DIST_SERVER</span><span class="token operator">=</span>https://mirrors.ustc.edu.cn/rust-static </span><span class="code-line"><span class="token class-name builtin">export</span> <span class="token variable assign-left">RUSTUP_UPDATE_ROOT</span><span class="token operator">=</span>https://mirrors.ustc.edu.cn/rust-static/rustup </span></code></pre></div><p>官方文档: <a href="https://mirrors.ustc.edu.cn/help/rust-static.html">https://mirrors.ustc.edu.cn/help/rust-static.html</a></p><p>编辑 ~/.cargo/config 文件,添加以下内容:</p><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source.crates-io</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">replace-with</span> <span class="token punctuation">=</span> <span class="token string">&#x27;ustc&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">source.ustc</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">registry</span> <span class="token punctuation">=</span> <span class="token string">&quot;git://mirrors.ustc.edu.cn/crates.io-index&quot;</span> </span></code></pre></div><p>如果所处的环境中不允许使用 git 协议,可以把上述地址改为:</p><p><code>registry = &quot;https://mirrors.ustc.edu.cn/crates.io-index&quot;</code></p><blockquote><p>警告: cargo search 无法使用镜像</p></blockquote><p>官方文档: <a href="https://mirrors.ustc.edu.cn/help/crates.io-index.html">https://mirrors.ustc.edu.cn/help/crates.io-index.html</a></p><h2 id="速度测试"><a href="#速度测试" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>速度测试</h2><p>我这边是南方电信, 注: 其中ustc没有提供镜像iso下载,而是重定向到了aliyun.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">curl</span> <span class="token variable parameter">-I</span> https://mirrors.ustc.edu.cn/fedora/releases/32/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line">HTTP/1.1 <span class="token number">200</span> Connection established </span><span class="code-line"> </span><span class="code-line">HTTP/2 <span class="token number">302</span> </span><span class="code-line">server: openresty </span><span class="code-line">date: Sat, <span class="token number">11</span> Jul <span class="token number">2020</span> 03:31:19 GMT </span><span class="code-line">content-type: text/html </span><span class="code-line">content-length: <span class="token number">142</span> </span><span class="code-line">location: https://mirrors.aliyun.com/fedora/releases/32/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso </span></code></pre></div><p>虽然都是教育网, 但是速度上还是差异较大的。阿里云的下载速度一般是不错的,但是以老灯以前的使用经验来看,偶尔会出点小问题,同时不及时或者cdn连接问题。</p><p>测试命令: 直接采用Fedora上的curl(支持<code>-Z, --parallel Perform transfers in parallel</code>参数以多线程方式下载) ,设置的传输时间为10秒.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">curl</span> <span class="token variable parameter">-m</span> <span class="token number">10</span> <span class="token variable parameter">-LZO</span> https://mirrors.sjtug.sjtu.edu.cn/fedora/linux/releases/32/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line"> </span><span class="code-line">DL% UL% Dled Uled Xfers Live Qd Total Current Left Speed </span><span class="code-line"> <span class="token number">20</span> -- 389M <span class="token number">0</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">0</span> <span class="token number">0</span>:00:46 <span class="token number">0</span>:00:09 <span class="token number">0</span>:00:36 <span class="token number">40</span>.3M curl: <span class="token punctuation">(</span><span class="token number">28</span><span class="token punctuation">)</span> Operation timed out after <span class="token number">10000</span> milliseconds with <span class="token number">426433583</span> out of <span class="token number">1966178304</span> bytes received </span><span class="code-line"> <span class="token number">21</span> -- 406M <span class="token number">0</span> <span class="token number">1</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token number">0</span>:00:46 <span class="token number">0</span>:00:10 <span class="token number">0</span>:00:36 <span class="token number">40</span>.7M </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">curl</span> <span class="token variable parameter">-m</span> <span class="token number">10</span> <span class="token variable parameter">-LZO</span> https://mirrors.aliyun.com/fedora/releases/32/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line">DL% UL% Dled Uled Xfers Live Qd Total Current Left Speed </span><span class="code-line"> <span class="token number">11</span> -- 221M <span class="token number">0</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">0</span> <span class="token number">0</span>:01:24 <span class="token number">0</span>:00:09 <span class="token number">0</span>:01:14 <span class="token number">22</span>.2M curl: <span class="token punctuation">(</span><span class="token number">28</span><span class="token punctuation">)</span> Operation timed out after <span class="token number">10000</span> milliseconds with <span class="token number">239353102</span> out of <span class="token number">1966178304</span> bytes received </span><span class="code-line"> <span class="token number">12</span> -- 228M <span class="token number">0</span> <span class="token number">1</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token number">0</span>:01:26 <span class="token number">0</span>:00:10 <span class="token number">0</span>:01:15 <span class="token number">21</span>.7M </span><span class="code-line"> </span><span class="code-line">❯ <span class="token function">curl</span> <span class="token variable parameter">-m</span> <span class="token number">10</span> <span class="token variable parameter">-LZO</span> https://mirrors.tuna.tsinghua.edu.cn/fedora/releases/32/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line">DL% UL% Dled Uled Xfers Live Qd Total Current Left Speed </span><span class="code-line"> <span class="token number">2</span> -- <span class="token number">52</span>.8M <span class="token number">0</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">0</span> <span class="token number">0</span>:09:03 <span class="token number">0</span>:00:10 <span class="token number">0</span>:08:47 3536k curl: <span class="token punctuation">(</span><span class="token number">28</span><span class="token punctuation">)</span> Operation timed out after <span class="token number">10001</span> milliseconds with <span class="token number">55427018</span> out of <span class="token number">1966178304</span> bytes received </span><span class="code-line"> <span class="token number">2</span> -- <span class="token number">52</span>.8M <span class="token number">0</span> <span class="token number">1</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token number">0</span>:16:03 <span class="token number">0</span>:00:10 <span class="token number">0</span>:15:35 1993k </span></code></pre></div><p>很明显,下载速度上sjtug打败了其它几家。 但是要注意的是, sjtug 的源支持数量 比 tuna 和 ustc 少很多。</p> Thu, 09 Jul 2020 16:43:26 GMT ttyS3 mirrorlinuxdocker-registrygoproxyrustupcrates https://ttys3.dev/blog/how-to-boot-fedora-live-cd-iso-from-grub2 如何从 grub2 启动 Fedora40 Live CD iso https://ttys3.dev/blog/how-to-boot-fedora-live-cd-iso-from-grub2 <p>20240325: Fedora 40</p><p><code>/etc/grub.d/40_custom</code></p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token important shebang">#!/usr/bin/sh</span> </span><span class="code-line"><span class="token builtin class-name">exec</span> <span class="token function">tail</span> <span class="token variable parameter">-n</span> +3 <span class="token variable">$0</span> </span><span class="code-line"><span class="token comment"># This file provides an easy way to add custom menu entries. Simply type the</span> </span><span class="code-line"><span class="token comment"># menu entries you want to add after this comment. Be careful not to change</span> </span><span class="code-line"><span class="token comment"># the &#x27;exec tail&#x27; line above.</span> </span><span class="code-line"> </span><span class="code-line">menuentry <span class="token string">&quot;Fedora Workstation 40 Live&quot;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment"># remove tpm mod to avoid out of memory err</span> </span><span class="code-line"> rmmod tpm </span><span class="code-line"> insmod all_video </span><span class="code-line"> <span class="token builtin class-name">set</span> <span class="token variable assign-left">gfxpayload</span><span class="token operator">=</span>keep </span><span class="code-line"> insmod gzio </span><span class="code-line"> insmod part_gpt </span><span class="code-line"> insmod ext2 </span><span class="code-line"> insmod chain </span><span class="code-line"> </span><span class="code-line"> <span class="token builtin class-name">set</span> <span class="token variable assign-left">isofile</span><span class="token operator">=</span><span class="token string">&quot;/iso/Fedora-Workstation-Live-x86_64-40_Beta-1.10.iso&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;Setting up loopback&quot;</span> </span><span class="code-line"> loopback loop <span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token variable assign-left">isolabel</span><span class="token operator">=</span><span class="token string">&quot;Fedora-WS-Live-40_B-1-10&quot;</span> </span><span class="code-line"> <span class="token comment"># fedora grub2 no probe command</span> </span><span class="code-line"> <span class="token comment">#probe -l loop --set=isolabel</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;ISO Label is <span class="token variable">${isolabel}</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;Booting....&quot;</span> </span><span class="code-line"> linux <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/images/pxeboot/vmlinuz iso-scan/filename<span class="token operator">=</span><span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> <span class="token variable assign-left">root</span><span class="token operator">=</span>live:CDLABEL<span class="token operator">=</span><span class="token variable">$isolabel</span> <span class="token variable assign-left">rootfstype</span><span class="token operator">=</span>auto ro rd.live.image noquiet <span class="token variable assign-left">rd.luks</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.md</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.dm</span><span class="token operator">=</span><span class="token number">0</span> </span><span class="code-line"> <span class="token comment"># disable KMS if getting a blank screen or a &quot;no signal&quot; error from the display, see https://wiki.archlinux.org/index.php/Kernel_mode_setting</span> </span><span class="code-line"> <span class="token comment"># nomodeset i915.modeset=0 nouveau.modeset=0 </span> </span><span class="code-line"> <span class="token comment"># nouveau.config=NvBios=PRAMIN video=HDMI-A-4:1920x1080@60</span> </span><span class="code-line"> <span class="token comment"># modprobe.blacklist=nouveau</span> </span><span class="code-line"> initrd <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/images/pxeboot/initrd.img </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><hr/><p>Fedora 39</p><p>添加 Live CD 启动项,主要用于系统挂了之后,我们还可以通过它来rescue</p><h2 id="下载live-cd"><a href="#下载live-cd" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>下载live cd</h2><p>从清华源下载比较快</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LZO</span> https://mirrors.tuna.tsinghua.edu.cn/fedora/releases/32/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> https://mirrors.tuna.tsinghua.edu.cn/fedora/releases/32/Workstation/x86_64/iso/Fedora-Workstation-32-1.6-x86_64-CHECKSUM </span></code></pre></div><p>下载成功后, 参考<a href="https://getfedora.org/en/security/">官方教程</a>校验iso</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 导入 Fedora&#x27;s GPG key</span> </span><span class="code-line"><span class="token function">curl</span> https://getfedora.org/static/fedora.gpg <span class="token operator">|</span> gpg <span class="token variable parameter">--import</span> </span><span class="code-line"><span class="token comment"># 校验CHECKSUM文件是否合法</span> </span><span class="code-line">gpg --verify-files *-CHECKSUM </span><span class="code-line"><span class="token comment"># 最后校验下载的iso的checksum是否一致</span> </span><span class="code-line">sha256sum <span class="token variable parameter">-c</span> *-CHECKSUM </span></code></pre></div><p>然后将文件copy到<code>/boot</code>下。为方便管理,我们在<code>/boot</code>下新建一<code>iso</code>目录, 然后将下载的live cd iso放于此:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">mkdir</span> /boot/iso </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">rsync</span> <span class="token variable parameter">-avP</span> ./Fedora-Workstation-Live-x86_64-32-1.6.iso /boot/iso/ </span></code></pre></div><p>注意,Fedora 这个 live iso 文件大小大概在 1.8GB, 确保你的 /boot 分区有足够大的空间。</p><p>老灯在创建 <code>/boot</code> 分区时就已经考虑到了这一点,给 <code>/boot</code> 分配了至少 4GB 的空间。</p><h2 id="增加grub2启动项"><a href="#增加grub2启动项" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>增加grub2启动项</h2><p>mount the iso</p><p>/run/media/ttys3/Fedora-WS-Live-39_B-1-1/EFI/BOOT/grub.cfg</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token attr-name key">set default</span><span class="token punctuation">=</span><span class="token attr-value value">&quot;<span class="token inner-value">1</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line">function load_video { </span><span class="code-line"> insmod efi_gop </span><span class="code-line"> insmod efi_uga </span><span class="code-line"> insmod video_bochs </span><span class="code-line"> insmod video_cirrus </span><span class="code-line"> insmod all_video </span><span class="code-line">} </span><span class="code-line"> </span><span class="code-line">load_video </span><span class="code-line"><span class="token attr-name key">set gfxpayload</span><span class="token punctuation">=</span><span class="token attr-value value">keep</span> </span><span class="code-line">insmod gzio </span><span class="code-line">insmod part_gpt </span><span class="code-line">insmod ext2 </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">set timeout</span><span class="token punctuation">=</span><span class="token attr-value value">60</span> </span><span class="code-line"><span class="token comment">### END /etc/grub.d/00_header ###</span> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">search --no-floppy --set</span><span class="token punctuation">=</span><span class="token attr-value value">root -l &#x27;Fedora-WS-Live-39_B-1-1&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">### BEGIN /etc/grub.d/10_linux ###</span> </span><span class="code-line">menuentry &#x27;Start Fedora-Workstation-Live 39_Beta&#x27; --class fedora --class gnu-linux --class gnu --class os { </span><span class="code-line"> <span class="token attr-name key">linuxefi /images/pxeboot/vmlinuz root</span><span class="token punctuation">=</span><span class="token attr-value value">live:CDLABEL=Fedora-WS-Live-39_B-1-1 rd.live.image quiet rhgb</span> </span><span class="code-line"> initrdefi /images/pxeboot/initrd.img </span><span class="code-line">} </span><span class="code-line">menuentry &#x27;Test this media &amp; start Fedora-Workstation-Live 39_Beta&#x27; --class fedora --class gnu-linux --class gnu --class os { </span><span class="code-line"> <span class="token attr-name key">linuxefi /images/pxeboot/vmlinuz root</span><span class="token punctuation">=</span><span class="token attr-value value">live:CDLABEL=Fedora-WS-Live-39_B-1-1 rd.live.image rd.live.check quiet</span> </span><span class="code-line"> initrdefi /images/pxeboot/initrd.img </span><span class="code-line">} </span><span class="code-line">submenu &#x27;Troubleshooting --&gt;&#x27; { </span><span class="code-line"> menuentry &#x27;Start Fedora-Workstation-Live 39_Beta in basic graphics mode&#x27; --class fedora --class gnu-linux --class gnu --class os { </span><span class="code-line"> <span class="token attr-name key">linuxefi /images/pxeboot/vmlinuz root</span><span class="token punctuation">=</span><span class="token attr-value value">live:CDLABEL=Fedora-WS-Live-39_B-1-1 rd.live.image nomodeset quiet rhgb</span> </span><span class="code-line"> initrdefi /images/pxeboot/initrd.img </span><span class="code-line"> } </span><span class="code-line">} </span></code></pre></div><p>grub2-mkconfig 在生成配置文件的时候,默认会读取 <code>/etc/grub.d/40_custom</code> ,这里就是我们添加iso启动项的地方了。</p><p>这个文件默认内容如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token important shebang">#!/usr/bin/sh</span> </span><span class="code-line"><span class="token builtin class-name">exec</span> <span class="token function">tail</span> <span class="token variable parameter">-n</span> +3 <span class="token variable">$0</span> </span><span class="code-line"><span class="token comment"># This file provides an easy way to add custom menu entries. Simply type the</span> </span><span class="code-line"><span class="token comment"># menu entries you want to add after this comment. Be careful not to change</span> </span><span class="code-line"><span class="token comment"># the &#x27;exec tail&#x27; line above.</span> </span></code></pre></div><p>千万注意不要删除<code>exec tail -n +3 $0</code>这一行及以上的内容。</p><p><code>tail -n +3 $0</code> 的意思是取本文件第3行(包括)及之后的内容, 第3行其实就是<code>exec</code>这一行之后的那一行了。</p><p>老灯的<code>/etc/grub.d/40_custom</code>文件内容如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token important shebang">#!/usr/bin/sh</span> </span><span class="code-line"><span class="token builtin class-name">exec</span> <span class="token function">tail</span> <span class="token variable parameter">-n</span> +3 <span class="token variable">$0</span> </span><span class="code-line"><span class="token comment"># This file provides an easy way to add custom menu entries. Simply type the</span> </span><span class="code-line"><span class="token comment"># menu entries you want to add after this comment. Be careful not to change</span> </span><span class="code-line"><span class="token comment"># the &#x27;exec tail&#x27; line above.</span> </span><span class="code-line">menuentry <span class="token string">&quot;Fedora Workstation 32 Live&quot;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment"># remove tpm mod to avoid out of memory err</span> </span><span class="code-line"> rmmod tpm </span><span class="code-line"> <span class="token builtin class-name">set</span> <span class="token variable assign-left">isofile</span><span class="token operator">=</span><span class="token string">&quot;/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;Setting up loopback&quot;</span> </span><span class="code-line"> loopback loop <span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token variable assign-left">isolabel</span><span class="token operator">=</span><span class="token string">&quot;Fedora-WS-Live-39_B-1-1&quot;</span> </span><span class="code-line"> <span class="token comment"># fedora grub2 no probe command</span> </span><span class="code-line"> <span class="token comment">#probe -l loop --set=isolabel</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;ISO Label is <span class="token variable">${isolabel}</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;Booting....&quot;</span> </span><span class="code-line"> linuxefi <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/images/pxeboot/vmlinuz iso-scan/filename<span class="token operator">=</span><span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> <span class="token variable assign-left">root</span><span class="token operator">=</span>live:CDLABEL<span class="token operator">=</span><span class="token variable">$isolabel</span> rd.live.image noquiet <span class="token variable assign-left">rd.luks</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.md</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.dm</span><span class="token operator">=</span><span class="token number">0</span> </span><span class="code-line"> initrdefi <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/images/pxeboot/initrd.img </span><span class="code-line"> </span><span class="code-line"> <span class="token comment"># disable KMS if getting a blank screen or a &quot;no signal&quot; error from the display, see https://wiki.archlinux.org/index.php/Kernel_mode_setting</span> </span><span class="code-line"> <span class="token comment">#nomodeset i915.modeset=0 nouveau.modeset=0</span> </span><span class="code-line"> <span class="token comment">#nouveau.config=NvBios=PRAMIN video=HDMI-A-4:1920x1080@60</span> </span><span class="code-line"> <span class="token comment">#modprobe.blacklist=nouveau</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>注意,这里一定要在加载loop设备之前,把<code>tpm</code>模块移除: <code>rmmod tpm</code>, 不然会遇到out of memory错误,无法加载iso</p><p>由于Fedora下的grub2没有<code>probe</code>命令,我们只能手动指定isolabel了。</p><p>iso 文件的 label 可以用 <code>iso-info</code> (由<code>libcdio</code>包提供)来读取:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ iso-info ~/Downloads/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line">iso-info version <span class="token number">2.0</span>.0 x86_64-redhat-linux-gnu </span><span class="code-line">Copyright <span class="token punctuation">(</span>c<span class="token punctuation">)</span> <span class="token number">2003</span>-2005, <span class="token number">2007</span>-2008, <span class="token number">2011</span>-2015, <span class="token number">2017</span> R. Bernstein </span><span class="code-line">This is <span class="token function">free</span> software<span class="token punctuation">;</span> see the <span class="token builtin class-name">source</span> <span class="token keyword">for</span> copying conditions. </span><span class="code-line">There is NO warranty<span class="token punctuation">;</span> not even <span class="token keyword">for</span> MERCHANTABILITY or FITNESS FOR A </span><span class="code-line">PARTICULAR PURPOSE. </span><span class="code-line">__________________________________ </span><span class="code-line">ISO <span class="token number">9660</span> image: /home/ttys3/Downloads/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line">Preparer <span class="token builtin class-name">:</span> XORRISO-1.5.2 <span class="token number">2019.10</span>.26.180001, LIBISOBURN-1.5.2, LIBISOFS-1.5.2, LIBBURN-1.5.2 </span><span class="code-line">Volume <span class="token builtin class-name">:</span> Fedora-WS-Live-32-1-6 </span><span class="code-line">Joliet Level: <span class="token number">3</span> </span></code></pre></div><p>然后我们就得到了label: <code>Fedora-WS-Live-32-1-6</code></p><p>一般情况下,内核命令行,我们使用下面这个就可以(上面默认的):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">linux <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/isolinux/vmlinuz iso-scan/filename<span class="token operator">=</span><span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> <span class="token variable assign-left">root</span><span class="token operator">=</span>live:CDLABEL<span class="token operator">=</span><span class="token variable">$isolabel</span> <span class="token variable assign-left">rootfstype</span><span class="token operator">=</span>auto ro rd.live.image noquiet <span class="token variable assign-left">rd.luks</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.md</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.dm</span><span class="token operator">=</span><span class="token number">0</span> </span></code></pre></div><p>但是,实际上老灯正在使用的cmdline是:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">linux <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/isolinux/vmlinuz iso-scan/filename<span class="token operator">=</span><span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> <span class="token variable assign-left">root</span><span class="token operator">=</span>live:CDLABEL<span class="token operator">=</span><span class="token variable">$isolabel</span> <span class="token variable assign-left">rootfstype</span><span class="token operator">=</span>auto ro rd.live.image noquiet <span class="token variable assign-left">rd.luks</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.md</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.dm</span><span class="token operator">=</span><span class="token number">0</span> nomodeset <span class="token variable assign-left">i915.modeset</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">nouveau.modeset</span><span class="token operator">=</span><span class="token number">0</span> </span></code></pre></div><p>老灯为什么多加了三个参数 <code>nomodeset i915.modeset=0 nouveau.modeset=0</code> ?主要是因为老灯的GeForce GTX 1060显卡 在Fedora加载了默认的<code>nouveau</code>开源驱动后,显示器会直接黑屏然后显示没有信号。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ lspci <span class="token variable parameter">-k</span> <span class="token operator">|</span> <span class="token function">grep</span> <span class="token variable parameter">-i</span> vga </span><span class="code-line">00:02.0 VGA compatible controller: Intel Corporation UHD Graphics <span class="token number">630</span> <span class="token punctuation">(</span>Desktop<span class="token punctuation">)</span> </span><span class="code-line">03:00.0 VGA compatible controller: NVIDIA Corporation GP106 <span class="token punctuation">[</span>GeForce GTX <span class="token number">1060</span> 3GB<span class="token punctuation">]</span> <span class="token punctuation">(</span>rev a1<span class="token punctuation">)</span> </span></code></pre></div><p>为了能使<code>nouveau</code>开源驱动能工作(能点亮显示器,能不崩就行了),老灯不得不关闭KMS (Kernel Mode Setting), 增加 <code>nouveau.modeset=0</code></p><p>由于<code>nouveau</code>开源驱动实际上是要依赖KMS才能正常工作的, 关闭KMS的后果是,整个图像和字体都显示得非常大,并且显示分辨率不可调整了。虽然如此,但是至少我们能进图形界面了。</p><p>这应该只是<code>nouveau</code>在GTX 1060下的问题吧。因为在其它NVIDIA硬件上,老灯发现<code>nouveau</code>驱动其实是工作良好的。</p><p>这里主要是查看了<a href="https://wiki.archlinux.org/index.php/Kernel_mode_setting#Disabling_modesetting">ArchLinux 关于 KMS 的文档</a>,问题才得到解决。</p><p>如果驱动能在KMS开启(默认开启的)的情况下正常工作,但是分辨率不太对,可以自行手动指定, 比如 <code>video=HDMI-A-4:1920x1080@60</code>。这里的<code>HDMI-A-4</code>是指的接口。 要查看当前哪些接口是处于连接状态的, 可以使用如下脚本:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token keyword">for</span> <span class="token variable for-or-select">p</span> <span class="token keyword">in</span> /sys/class/drm/*/status<span class="token punctuation">;</span> <span class="token keyword">do</span> <span class="token variable assign-left">con</span><span class="token operator">=</span><span class="token variable">${p<span class="token operator">%</span><span class="token operator">/</span>status}</span><span class="token punctuation">;</span> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-n</span> <span class="token string">&quot;<span class="token variable">${con<span class="token operator">#</span>*<span class="token operator">/</span>card?-}</span>: &quot;</span><span class="token punctuation">;</span> <span class="token function">cat</span> <span class="token variable">$p</span><span class="token punctuation">;</span> <span class="token keyword">done</span> </span></code></pre></div><p>老灯这里只接了一个显示器, 运行结果如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token keyword">for</span> <span class="token variable for-or-select">p</span> <span class="token keyword">in</span> /sys/class/drm/*/status<span class="token punctuation">;</span> <span class="token keyword">do</span> <span class="token variable assign-left">con</span><span class="token operator">=</span><span class="token variable">${p<span class="token operator">%</span><span class="token operator">/</span>status}</span><span class="token punctuation">;</span> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-n</span> <span class="token string">&quot;<span class="token variable">${con<span class="token operator">#</span>*<span class="token operator">/</span>card?-}</span>: &quot;</span><span class="token punctuation">;</span> <span class="token function">cat</span> <span class="token variable">$p</span><span class="token punctuation">;</span> <span class="token keyword">done</span> </span><span class="code-line">DP-1: disconnected </span><span class="code-line">HDMI-A-1: disconnected </span><span class="code-line">HDMI-A-2: disconnected </span><span class="code-line">HDMI-A-3: disconnected </span><span class="code-line">DP-2: disconnected </span><span class="code-line">DVI-D-1: disconnected </span><span class="code-line">HDMI-A-4: connected </span></code></pre></div><p>如果<code>nouveau</code>驱动怎么折腾都不工作,可以禁用它 <code>modprobe.blacklist=nouveau</code>, 这样至少可以通过按 <code>Ctrl + alt + Fx</code> 进入纯控制台。</p><p>另外,Intel的<code>i915</code>驱动兼容性一般很好,很少会有黑屏问题。</p><h2 id="re-generate-grub2cfg"><a href="#re-generate-grub2cfg" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>re-generate grub2.cfg</h2><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">sudo</span> grub2-mkconfig <span class="token variable parameter">-o</span> /etc/grub2-efi.cfg </span></code></pre></div><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://wiki.archlinux.org/index.php/Nouveau">https://wiki.archlinux.org/index.php/Nouveau</a></p><p><a href="https://wiki.archlinux.org/index.php/Kernel_mode_setting#Disabling_modesetting">https://wiki.archlinux.org/index.php/Kernel_mode_setting#Disabling_modesetting</a></p><p><a href="https://wiki.archlinux.org/index.php/Kernel_mode_setting#Forcing_modes">https://wiki.archlinux.org/index.php/Kernel_mode_setting#Forcing_modes</a></p><p><a href="https://help.ubuntu.com/community/Grub2/ISOBoot">https://help.ubuntu.com/community/Grub2/ISOBoot</a></p><p><a href="https://forums.freeside.co.uk/t/how-to-boot-a-fedora-30-iso-from-grub/197">https://forums.freeside.co.uk/t/how-to-boot-a-fedora-30-iso-from-grub/197</a></p><p><a href="https://fedoramagazine.org/start-a-fedora-29-installation-from-the-grub-menu/">https://fedoramagazine.org/start-a-fedora-29-installation-from-the-grub-menu/</a></p> Sat, 27 Jun 2020 06:31:33 GMT ttyS3 grub2fedoraiso https://ttys3.dev/blog/how-to-boot-fedora32-live-cd-iso-from-grub2 如何从 grub2 启动 Fedora32 Live CD iso https://ttys3.dev/blog/how-to-boot-fedora32-live-cd-iso-from-grub2 <p>添加 Live CD 启动项,主要用于系统挂了之后,我们还可以通过它来rescue</p><h2 id="下载live-cd"><a href="#下载live-cd" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>下载live cd</h2><p>从清华源下载比较快</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LZO</span> https://mirrors.tuna.tsinghua.edu.cn/fedora/releases/32/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line"><span class="token function">curl</span> <span class="token variable parameter">-LO</span> https://mirrors.tuna.tsinghua.edu.cn/fedora/releases/32/Workstation/x86_64/iso/Fedora-Workstation-32-1.6-x86_64-CHECKSUM </span></code></pre></div><p>下载成功后, 参考<a href="https://getfedora.org/en/security/">官方教程</a>校验iso</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 导入 Fedora&#x27;s GPG key</span> </span><span class="code-line"><span class="token function">curl</span> https://getfedora.org/static/fedora.gpg <span class="token operator">|</span> gpg <span class="token variable parameter">--import</span> </span><span class="code-line"><span class="token comment"># 校验CHECKSUM文件是否合法</span> </span><span class="code-line">gpg --verify-files *-CHECKSUM </span><span class="code-line"><span class="token comment"># 最后校验下载的iso的checksum是否一致</span> </span><span class="code-line">sha256sum <span class="token variable parameter">-c</span> *-CHECKSUM </span></code></pre></div><p>然后将文件copy到<code>/boot</code>下。为方便管理,我们在<code>/boot</code>下新建一<code>iso</code>目录, 然后将下载的live cd iso放于此:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">mkdir</span> /boot/iso </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">rsync</span> <span class="token variable parameter">-avP</span> ./Fedora-Workstation-Live-x86_64-32-1.6.iso /boot/iso/ </span></code></pre></div><p>注意,Fedora 这个 live iso 文件大小大概在 1.8GB, 确保你的 /boot 分区有足够大的空间。</p><p>老灯在创建 <code>/boot</code> 分区时就已经考虑到了这一点,给 <code>/boot</code> 分配了至少 4GB 的空间。</p><h2 id="增加grub2启动项"><a href="#增加grub2启动项" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>增加grub2启动项</h2><p>grub2-mkconfig 在生成配置文件的时候,默认会读取 <code>/etc/grub.d/40_custom</code> ,这里就是我们添加iso启动项的地方了。</p><p>这个文件默认内容如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token important shebang">#!/usr/bin/sh</span> </span><span class="code-line"><span class="token builtin class-name">exec</span> <span class="token function">tail</span> <span class="token variable parameter">-n</span> +3 <span class="token variable">$0</span> </span><span class="code-line"><span class="token comment"># This file provides an easy way to add custom menu entries. Simply type the</span> </span><span class="code-line"><span class="token comment"># menu entries you want to add after this comment. Be careful not to change</span> </span><span class="code-line"><span class="token comment"># the &#x27;exec tail&#x27; line above.</span> </span></code></pre></div><p>千万注意不要删除<code>exec tail -n +3 $0</code>这一行及以上的内容。</p><p><code>tail -n +3 $0</code> 的意思是取本文件第3行(包括)及之后的内容, 第3行其实就是<code>exec</code>这一行之后的那一行了。</p><p>老灯的<code>/etc/grub.d/40_custom</code>文件内容如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token important shebang">#!/usr/bin/sh</span> </span><span class="code-line"><span class="token builtin class-name">exec</span> <span class="token function">tail</span> <span class="token variable parameter">-n</span> +3 <span class="token variable">$0</span> </span><span class="code-line"><span class="token comment"># This file provides an easy way to add custom menu entries. Simply type the</span> </span><span class="code-line"><span class="token comment"># menu entries you want to add after this comment. Be careful not to change</span> </span><span class="code-line"><span class="token comment"># the &#x27;exec tail&#x27; line above.</span> </span><span class="code-line">menuentry <span class="token string">&quot;Fedora Workstation 32 Live&quot;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment"># remove tpm mod to avoid out of memory err</span> </span><span class="code-line"> rmmod tpm </span><span class="code-line"> <span class="token builtin class-name">set</span> <span class="token variable assign-left">isofile</span><span class="token operator">=</span><span class="token string">&quot;/iso/Fedora-Workstation-Live-x86_64-32-1.6.iso&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;Setting up loopback&quot;</span> </span><span class="code-line"> loopback loop <span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token variable assign-left">isolabel</span><span class="token operator">=</span><span class="token string">&quot;Fedora-WS-Live-32-1-6&quot;</span> </span><span class="code-line"> <span class="token comment"># fedora grub2 no probe command</span> </span><span class="code-line"> <span class="token comment">#probe -l loop --set=isolabel</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;ISO Label is <span class="token variable">${isolabel}</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token string">&quot;Booting....&quot;</span> </span><span class="code-line"> linux <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/isolinux/vmlinuz iso-scan/filename<span class="token operator">=</span><span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> <span class="token variable assign-left">root</span><span class="token operator">=</span>live:CDLABEL<span class="token operator">=</span><span class="token variable">$isolabel</span> <span class="token variable assign-left">rootfstype</span><span class="token operator">=</span>auto ro rd.live.image noquiet <span class="token variable assign-left">rd.luks</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.md</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.dm</span><span class="token operator">=</span><span class="token number">0</span> </span><span class="code-line"> <span class="token comment"># disable KMS if getting a blank screen or a &quot;no signal&quot; error from the display, see https://wiki.archlinux.org/index.php/Kernel_mode_setting</span> </span><span class="code-line"> <span class="token comment">#linux (loop)/isolinux/vmlinuz iso-scan/filename=&quot;${isofile}&quot; root=live:CDLABEL=$isolabel rootfstype=auto ro rd.live.image noquiet rd.luks=0 rd.md=0 rd.dm=0 nomodeset i915.modeset=0 nouveau.modeset=0</span> </span><span class="code-line"> <span class="token comment">#linux (loop)/isolinux/vmlinuz iso-scan/filename=&quot;${isofile}&quot; root=live:CDLABEL=$isolabel rootfstype=auto ro rd.live.image noquiet rd.luks=0 rd.md=0 rd.dm=0 nouveau.config=NvBios=PRAMIN video=HDMI-A-4:1920x1080@60</span> </span><span class="code-line"> <span class="token comment">#linux (loop)/isolinux/vmlinuz iso-scan/filename=&quot;${isofile}&quot; root=live:CDLABEL=$isolabel rootfstype=auto ro rd.live.image noquiet rd.luks=0 rd.md=0 rd.dm=0 modprobe.blacklist=nouveau</span> </span><span class="code-line"> initrd <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/isolinux/initrd.img </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>注意,这里一定要在加载loop设备之前,把<code>tpm</code>模块移除: <code>rmmod tpm</code>, 不然会遇到out of memory错误,无法加载iso</p><p>由于Fedora下的grub2没有<code>probe</code>命令,我们只能手动指定isolabel了。</p><p>iso 文件的 label 可以用 <code>iso-info</code> (由<code>libcdio</code>包提供)来读取:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ iso-info ~/Downloads/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line">iso-info version <span class="token number">2.0</span>.0 x86_64-redhat-linux-gnu </span><span class="code-line">Copyright <span class="token punctuation">(</span>c<span class="token punctuation">)</span> <span class="token number">2003</span>-2005, <span class="token number">2007</span>-2008, <span class="token number">2011</span>-2015, <span class="token number">2017</span> R. Bernstein </span><span class="code-line">This is <span class="token function">free</span> software<span class="token punctuation">;</span> see the <span class="token builtin class-name">source</span> <span class="token keyword">for</span> copying conditions. </span><span class="code-line">There is NO warranty<span class="token punctuation">;</span> not even <span class="token keyword">for</span> MERCHANTABILITY or FITNESS FOR A </span><span class="code-line">PARTICULAR PURPOSE. </span><span class="code-line">__________________________________ </span><span class="code-line">ISO <span class="token number">9660</span> image: /home/ttys3/Downloads/Fedora-Workstation-Live-x86_64-32-1.6.iso </span><span class="code-line">Preparer <span class="token builtin class-name">:</span> XORRISO-1.5.2 <span class="token number">2019.10</span>.26.180001, LIBISOBURN-1.5.2, LIBISOFS-1.5.2, LIBBURN-1.5.2 </span><span class="code-line">Volume <span class="token builtin class-name">:</span> Fedora-WS-Live-32-1-6 </span><span class="code-line">Joliet Level: <span class="token number">3</span> </span></code></pre></div><p>然后我们就得到了label: <code>Fedora-WS-Live-32-1-6</code></p><p>一般情况下,内核命令行,我们使用下面这个就可以(上面默认的):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">linux <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/isolinux/vmlinuz iso-scan/filename<span class="token operator">=</span><span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> <span class="token variable assign-left">root</span><span class="token operator">=</span>live:CDLABEL<span class="token operator">=</span><span class="token variable">$isolabel</span> <span class="token variable assign-left">rootfstype</span><span class="token operator">=</span>auto ro rd.live.image noquiet <span class="token variable assign-left">rd.luks</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.md</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.dm</span><span class="token operator">=</span><span class="token number">0</span> </span></code></pre></div><p>但是,实际上老灯正在使用的cmdline是:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">linux <span class="token punctuation">(</span>loop<span class="token punctuation">)</span>/isolinux/vmlinuz iso-scan/filename<span class="token operator">=</span><span class="token string">&quot;<span class="token variable">${isofile}</span>&quot;</span> <span class="token variable assign-left">root</span><span class="token operator">=</span>live:CDLABEL<span class="token operator">=</span><span class="token variable">$isolabel</span> <span class="token variable assign-left">rootfstype</span><span class="token operator">=</span>auto ro rd.live.image noquiet <span class="token variable assign-left">rd.luks</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.md</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">rd.dm</span><span class="token operator">=</span><span class="token number">0</span> nomodeset <span class="token variable assign-left">i915.modeset</span><span class="token operator">=</span><span class="token number">0</span> <span class="token variable assign-left">nouveau.modeset</span><span class="token operator">=</span><span class="token number">0</span> </span></code></pre></div><p>老灯为什么多加了三个参数 <code>nomodeset i915.modeset=0 nouveau.modeset=0</code> ?主要是因为老灯的GeForce GTX 1060显卡 在Fedora加载了默认的<code>nouveau</code>开源驱动后,显示器会直接黑屏然后显示没有信号。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ lspci <span class="token variable parameter">-k</span> <span class="token operator">|</span> <span class="token function">grep</span> <span class="token variable parameter">-i</span> vga </span><span class="code-line">00:02.0 VGA compatible controller: Intel Corporation UHD Graphics <span class="token number">630</span> <span class="token punctuation">(</span>Desktop<span class="token punctuation">)</span> </span><span class="code-line">03:00.0 VGA compatible controller: NVIDIA Corporation GP106 <span class="token punctuation">[</span>GeForce GTX <span class="token number">1060</span> 3GB<span class="token punctuation">]</span> <span class="token punctuation">(</span>rev a1<span class="token punctuation">)</span> </span></code></pre></div><p>为了能使<code>nouveau</code>开源驱动能工作(能点亮显示器,能不崩就行了),老灯不得不关闭KMS (Kernel Mode Setting), 增加 <code>nouveau.modeset=0</code></p><p>由于<code>nouveau</code>开源驱动实际上是要依赖KMS才能正常工作的, 关闭KMS的后果是,整个图像和字体都显示得非常大,并且显示分辨率不可调整了。虽然如此,但是至少我们能进图形界面了。</p><p>这应该只是<code>nouveau</code>在GTX 1060下的问题吧。因为在其它NVIDIA硬件上,老灯发现<code>nouveau</code>驱动其实是工作良好的。</p><p>这里主要是查看了<a href="https://wiki.archlinux.org/index.php/Kernel_mode_setting#Disabling_modesetting">ArchLinux 关于 KMS 的文档</a>,问题才得到解决。</p><p>如果驱动能在KMS开启(默认开启的)的情况下正常工作,但是分辨率不太对,可以自行手动指定, 比如 <code>video=HDMI-A-4:1920x1080@60</code>。这里的<code>HDMI-A-4</code>是指的接口。 要查看当前哪些接口是处于连接状态的, 可以使用如下脚本:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token keyword">for</span> <span class="token variable for-or-select">p</span> <span class="token keyword">in</span> /sys/class/drm/*/status<span class="token punctuation">;</span> <span class="token keyword">do</span> <span class="token variable assign-left">con</span><span class="token operator">=</span><span class="token variable">${p<span class="token operator">%</span><span class="token operator">/</span>status}</span><span class="token punctuation">;</span> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-n</span> <span class="token string">&quot;<span class="token variable">${con<span class="token operator">#</span>*<span class="token operator">/</span>card?-}</span>: &quot;</span><span class="token punctuation">;</span> <span class="token function">cat</span> <span class="token variable">$p</span><span class="token punctuation">;</span> <span class="token keyword">done</span> </span></code></pre></div><p>老灯这里只接了一个显示器, 运行结果如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token keyword">for</span> <span class="token variable for-or-select">p</span> <span class="token keyword">in</span> /sys/class/drm/*/status<span class="token punctuation">;</span> <span class="token keyword">do</span> <span class="token variable assign-left">con</span><span class="token operator">=</span><span class="token variable">${p<span class="token operator">%</span><span class="token operator">/</span>status}</span><span class="token punctuation">;</span> <span class="token builtin class-name">echo</span> <span class="token variable parameter">-n</span> <span class="token string">&quot;<span class="token variable">${con<span class="token operator">#</span>*<span class="token operator">/</span>card?-}</span>: &quot;</span><span class="token punctuation">;</span> <span class="token function">cat</span> <span class="token variable">$p</span><span class="token punctuation">;</span> <span class="token keyword">done</span> </span><span class="code-line">DP-1: disconnected </span><span class="code-line">HDMI-A-1: disconnected </span><span class="code-line">HDMI-A-2: disconnected </span><span class="code-line">HDMI-A-3: disconnected </span><span class="code-line">DP-2: disconnected </span><span class="code-line">DVI-D-1: disconnected </span><span class="code-line">HDMI-A-4: connected </span></code></pre></div><p>如果<code>nouveau</code>驱动怎么折腾都不工作,可以禁用它 <code>modprobe.blacklist=nouveau</code>, 这样至少可以通过按 <code>Ctrl + alt + Fx</code> 进入纯控制台。</p><p>另外,Intel的<code>i915</code>驱动兼容性一般很好,很少会有黑屏问题。</p><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://wiki.archlinux.org/index.php/Nouveau">https://wiki.archlinux.org/index.php/Nouveau</a></p><p><a href="https://wiki.archlinux.org/index.php/Kernel_mode_setting#Disabling_modesetting">https://wiki.archlinux.org/index.php/Kernel_mode_setting#Disabling_modesetting</a></p><p><a href="https://wiki.archlinux.org/index.php/Kernel_mode_setting#Forcing_modes">https://wiki.archlinux.org/index.php/Kernel_mode_setting#Forcing_modes</a></p><p><a href="https://help.ubuntu.com/community/Grub2/ISOBoot">https://help.ubuntu.com/community/Grub2/ISOBoot</a></p><p><a href="https://forums.freeside.co.uk/t/how-to-boot-a-fedora-30-iso-from-grub/197">https://forums.freeside.co.uk/t/how-to-boot-a-fedora-30-iso-from-grub/197</a></p><p><a href="https://fedoramagazine.org/start-a-fedora-29-installation-from-the-grub-menu/">https://fedoramagazine.org/start-a-fedora-29-installation-from-the-grub-menu/</a></p> Sat, 27 Jun 2020 06:31:33 GMT ttyS3 grub2fedoraiso https://ttys3.dev/blog/fucked-up-by-ubuntu-20.04 Fucked Up by Ubuntu 20.04 https://ttys3.dev/blog/fucked-up-by-ubuntu-20.04 <h2 id="缘由及发行版的选择"><a href="#缘由及发行版的选择" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由及发行版的选择</h2><p>先说一下结果吧: 由于工作需要,我将一台工作PC台式机安装成了 Ubuntu 20.04。</p><p>如果想直接看fucked up部分,请直从右则的TOC接跳到 <code>#fucked-up</code></p><p>作为一个长期在Linux 桌面环境下工作的人,肯定是用新不用旧。新版本出来了,当然是上新版本。没点追求的话,人活着跟咸鱼有什么区别?</p><p>当然,老灯主要在用的还是Fedora. 选择哪个发行版也不是盲目选的,是根据个人需求的。</p><ol><li>肯定是选主流发行版,看重官方支持和更新维护。</li><li>Gnome 3 环境是优秀的,并且我已长期习惯这个环境了,因此 DE 必须是 Gnome 3</li><li>由于需要<strong>原生</strong>的Docker或Podman环境,因此只能是Linux系,BSD或其它系不考虑(包括苹果)</li><li>考虑到是工作环境使用,滚动升级的发行版就不考虑了。有一定的稳定性要求。</li><li>作为工作开发环境,不能是太守旧的发行版,比如Debian或CentOS就不考虑了</li></ol><p>打开 <a href="https://distrowatch.com/dwres.php?resource=major">distrowatch</a> 看看主流发行版吧。</p><ul><li>Linux Mint: 主要版本为基于Ubuntu的,DE为Cinnamon, MATE 和 Xfce, 没有 Gnome 3, 放弃。</li><li>Ubuntu: 主版本为Gnome 3环境,背后有Canonical公司支撑,有稳定的版本更新和发行周期,软件包一般较新。可作为候选。</li><li>MX Linux: 这是怎么上到这个列表的?没听过,不好意思。</li><li>Arch Linux: 老灯此前用过10多年, pacman非常灵活,文档最友好(没有之一),滚动升级,软件包升级非常及时,主要的不稳定性因素,可能来自厂家显卡驱动。因为Arch是滚动升级,且内核升级是相当激进,基本上是跟随mainline内核版本的,而厂商的显卡驱动可能没有那么快发布对较新内核的支持,工作中很可能导致大早上一升级崩了,一上午都在修系统。因此不太适合在工作中使用。</li><li>Gentoo: 安装系统需要一定的技能,安装包以编译为主,较为耗时,不利于提升工作效率。几十年来老灯一直没有尝试这个系统的想法。</li><li>Slackware: 略冷门,用得人比较少,有个叫unRAID的 NAS 系统好像是基于它的,不是老灯的菜。放弃。</li><li>Debian: 社区主导,版本发行周期较长且无固定时间,稳定性著称,一直守着点老包,有bug了就修一下,能不稳定吗?问题是,当大家都在用win10的时候,我不想还在用win7。 所以,放弃。</li><li>Fedora: 主版本为Gnome 3环境,软件包升级速度跟Arch有得一拼, 可能是主流里面,除了Arch之外,升级最激进的一个发行版。半年发行一个版本。有Red Hat这种商业公司在背后支持。可作为候选。</li><li>openSUSE: 同时支持KDE和 GNOME 3 环境。有SUSE LLC.这种商业公司在背后支撑。但是其主打 btrfs 和 KDE 桌面 (在安装界面, GNOME 一直是排在 KDE 后面)。</li></ul><p>截止到目前(2020-06-26) Docker 官方尚未提供 Fedora 32的 Docker repo。</p><p>见 <a href="https://github.com/docker/for-linux/issues/955">https://github.com/docker/for-linux/issues/955</a> , 虽然这里可以看到有个PR已经在 2020-04-11 merged: <a href="https://github.com/docker/docker-ce-packaging/pull/452">https://github.com/docker/docker-ce-packaging/pull/452</a> 但是 Ubuntu 20.04 和 Fedora 32 的发布时间相差没几天,Ubuntu 20.04 (代号Focal) 的 repo <a href="https://download.docker.com/linux/ubuntu/dists/focal/">https://download.docker.com/linux/ubuntu/dists/focal/</a> 早已OK,而 Fedora 的 repo 则还停留在 31 (见 <a href="https://download.docker.com/linux/fedora/">https://download.docker.com/linux/fedora/</a> ),同时 RHEL 和 CentOS 的 repo 也都还停留在 7, 最新的 8 是没有的。</p><p>老灯猜测,可能是跟 RHEL 对于 Docker 的态度有关 (见 <a href="https://www.techrepublic.com/article/a-matter-of-license-and-lock-in/">https://www.techrepublic.com/article/a-matter-of-license-and-lock-in/</a> ), 又或者是跟 Fedora 32 的 cgroup v2 和 nftables 有关。</p><p>由于项目需要用到 Docker, 而我也不想自己去手动把 Docker的 构建脚本修改成 Podman 适用的。 另外,podman的在非root用户时是以rootless模式运行,而该模式跟root模式相比,还存在较多的限制及坑。 因此,相对来说,如果要以当前(普通用户的身份)来构建镜像或运行容器,通过 Docker (将当前用户加入docker用户组)的方式兼容性更好。</p><p>因此,虽然老灯非常喜欢 Fedora, 但是还是不能选它。理由:不要自己给自己找麻烦。</p><p>openSUSE 历史上是以 KDE 为默认桌面环境的,后面虽然推出了 KDE, 但在安装界面, GNOME 选项还是排在 KDE 后面。另外,它默认用的 btrfs 使我有点担心。 因此,很自然地只剩下 Ubuntu 可选了。</p><blockquote><p>注意: 并不是说 Fedora 32 完全没有办法使用 Docker (事实上民间有文章介绍了直接使用f31的docker仓库的方法), 但是民间终归是民间,我需要的是一个持续的,稳定的支持, 而不是依靠民间的Hacking方法。</p></blockquote><h2 id="安装过程的小波折"><a href="#安装过程的小波折" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装过程的小波折</h2><p>从清华源下载iso: <a href="https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/focal/ubuntu-20.04-desktop-amd64.iso">https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/focal/ubuntu-20.04-desktop-amd64.iso</a></p><p>同时,一定要注意校验hash <a href="https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/focal/SHA256SUMS">https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/focal/SHA256SUMS</a></p><p>老灯这台工作机有两个硬盘,主盘nvme用来装操作系统,还有一个机械硬盘用于存数据。</p><p>机械硬盘暂时没存什么东西,因此,直接干掉了,然后用 dd 将 <code>ubuntu-20.04-desktop-amd64.iso</code> 写入 <code>/dev/sda</code> (机械硬盘)。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">dd</span> <span class="token variable assign-left">if</span><span class="token operator">=</span>./ubuntu-20.04-desktop-amd64.iso <span class="token variable assign-left">of</span><span class="token operator">=</span>/dev/sda <span class="token variable assign-left">bs</span><span class="token operator">=</span>8M </span></code></pre></div><blockquote><p>注意: /dev/sda 是我当前环境里的空闲磁盘,不可照抄。请根据自己的实际情况选择正确的磁盘设备。</p></blockquote><p>通过设置BIOS优先从机械硬盘启动,成功启动Ubuntu live, 然后 ubuntu 开始校验cd内容, 提示发现一个错误,但是 ubuntu 这一点有点坑, 没有阻止继续安装,而只是提示,此错误可能会导致安装失败。然后我抱着试一试的态度,直接继续安装。导致了悲具。 现在问题来了,原来nvme是有正常工作的系统的,现在已经在 ubuntu 安装过程中被干掉了,而这个live cd又是坏的。</p><p>我的想法是,直接在live系统里,重新下载iso并校验OK, 然后再通过 dd 写入 <code>/dev/sda</code> (机械硬盘), 再重启,重新开始安装。</p><p>iso下载完了,你会发现 <code>/dev/sda1</code> 是被挂载到了 <code>/cdrom</code>的,并且无法被 <code>umount</code>, 但是不影响 <code>dd</code> 直接写入 <code>/dev/sda</code></p><p>最终操作如期完成了。</p><p>来自老灯的警告: 如果 ubuntu live cd 提示你校验遇到错误了,不要继续安装,重新下载并注意校验 iso</p><p>安装系统时注意勾选 安装additional drivers选项,这样会自动判断显卡并选择最合适的驱动安装。 当然,这个也可以在系统安装完成后调整 (About - Software Updates - Additional Drivers)。</p><div><img alt="nvdia-driver.jpg" src="https://ttys3.dev/static/assets/nvdia-driver-JJCJX7GT.jpg" width="1309" height="879"/></div><div><img alt="ubuntu-drivers-list.jpg" src="https://ttys3.dev/static/assets/ubuntu-drivers-list-76TYKHAZ.jpg" width="927" height="296"/></div><p>按惯例,执行一下neofetch:</p><div><img alt="neofetch-with-desktop-background.jpg" src="https://ttys3.dev/static/assets/neofetch-with-desktop-background-5PFCSFGJ.jpg" width="1917" height="1072"/></div><p>连文件管理器配色都带着浓浓的Ubuntu logo味儿:</p><div><img alt="filemanager-style.jpg" src="https://ttys3.dev/static/assets/filemanager-style-P6ORDCSR.jpg" width="1408" height="824"/></div><p>关于信息:</p><div><img alt="ubuntu-about.jpg" src="https://ttys3.dev/static/assets/ubuntu-about-5YLA7P3E.jpg" width="1143" height="847"/></div><h2 id="环境配置"><a href="#环境配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>环境配置</h2><p>安装完成首先把系统升级到最新:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> update </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> upgrade </span></code></pre></div><h3 id="常用软件"><a href="#常用软件" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>常用软件</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> <span class="token function">vim</span> <span class="token function">htop</span> nload ncdu ripgrep gnome-tweaks <span class="token function">zsh</span> </span></code></pre></div><p>嫌弃 Ubuntu 默认的 terminal 背景配色的,可以使用 base16 的配色 <a href="https://github.com/aaron-williamson/base16-gnome-terminal">https://github.com/aaron-williamson/base16-gnome-terminal</a></p><h3 id="cockpit和kvm虚拟机"><a href="#cockpit和kvm虚拟机" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>cockpit和kvm虚拟机</h3><p>cockpit 是一个由 Red Hat 赞助的项目,主要是方便从WEB界面管理 Linux 服务器, 这个已经成为了 RHEL8 和 CentOS8 的标配。 老灯这里安装 cockpit 主要是 方便管理 kvm 虚拟机。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> <span class="token variable parameter">-y</span> cockpit cockpit-dashboard cockpit-machines cockpit-networkmanager cockpit-storaged cockpit-system cockpit-ws </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># ubuntu 上安装完默认是自动启用 和 启动 的</span> </span><span class="code-line"><span class="token function">sudo</span> systemctl status cockpit.socket </span></code></pre></div><p>这里有一个问题是,网络不是默认启动(激活)的(虽然默认的<code>default</code>网络已经创建好了, 这个问题在 Fedora 和 CentOS 上并不存在),解决办法 (来自 <a href="https://blog.programster.org/kvm-missing-default-network">https://blog.programster.org/kvm-missing-default-network</a> ):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">virsh</span> net-autostart <span class="token variable parameter">--network</span> default </span></code></pre></div><p>虚拟机创建的话,我直接使用我之前打造好的 win10 镜像,创建虚拟机很简单,直接使用 cockpit 界面的导入功能导入.qcow2 镜像即可。 导入后注意把相关的io修改成virtio模式(比如网卡, 磁盘)然后再启动。</p><div><img alt="cockpit-login-page.jpg" src="https://ttys3.dev/static/assets/cockpit-login-page-ABMBRB5N.jpg" width="1914" height="877"/></div><div><img alt="cockpit-vm-overview.jpg" src="https://ttys3.dev/static/assets/cockpit-vm-overview-JXGSFANM.jpg" width="1894" height="695"/></div><div><img alt="cockpit-vm.jpg" src="https://ttys3.dev/static/assets/cockpit-vm-CT5LLURS.jpg" width="1892" height="829"/></div><div><img alt="kvm-win10-guest.jpg" src="https://ttys3.dev/static/assets/kvm-win10-guest-EMY6H2PG.jpg" width="1396" height="913"/></div><p>windows 10 guest 怎么和 host 机共享文件呢? 最简单的方法是通过smb协议。</p><p>在 host 机,也就是 Ubuntu 上安装 samba:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> samba </span></code></pre></div><p>编辑 <code>/etc/samba/smb.conf</code>, 增加:</p><p>假设我们有一个用户 <code>ttys3</code> :</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">winshare</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">comment</span> <span class="token punctuation">=</span> <span class="token attr-value value">Media share accessible by kvm win guest</span> </span><span class="code-line"> <span class="token attr-name key">path</span> <span class="token punctuation">=</span> <span class="token attr-value value">/home/ttys3/winshare</span> </span><span class="code-line"> <span class="token attr-name key">valid users</span> <span class="token punctuation">=</span> <span class="token attr-value value">ttys3</span> </span><span class="code-line"> <span class="token attr-name key">public</span> <span class="token punctuation">=</span> <span class="token attr-value value">no</span> </span><span class="code-line"> <span class="token attr-name key">writable</span> <span class="token punctuation">=</span> <span class="token attr-value value">yes</span> </span><span class="code-line"> <span class="token attr-name key">create mask</span> <span class="token punctuation">=</span> <span class="token attr-value value">0664</span> </span><span class="code-line"> <span class="token attr-name key">directory mask</span> <span class="token punctuation">=</span> <span class="token attr-value value">2775</span> </span><span class="code-line"> <span class="token attr-name key">force create mode</span> <span class="token punctuation">=</span> <span class="token attr-value value">0664</span> </span><span class="code-line"> <span class="token attr-name key">force directory mode</span> <span class="token punctuation">=</span> <span class="token attr-value value">2775</span> </span></code></pre></div><p>虽然 Linux 已经有 <code>ttys3</code> 这个用户了,但是samba里面有另一套用户权限控制机制(注意:samba用户一定要是已经存在的Linux用户), 但是我们还是要将这个用户添加进samba:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">smbpasswd <span class="token variable parameter">-a</span> ttys3 </span><span class="code-line"><span class="token comment"># 然后设置密码(注意这里的密钥是用于设置samba用户的密码,新设置的,并不是要你输入系统用户的)</span> </span></code></pre></div><p>然后重启 smbd 和 nmbd:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> systemctl restart smbd nmbd </span></code></pre></div><p>win10 guest 机里可以用 <code>net use</code> 命令映射(192.168.0.x是host机的LAN ip):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">net use z: <span class="token punctuation">\</span><span class="token punctuation">\</span><span class="token number">192.168</span>.0.x<span class="token punctuation">\</span>winshare /user:ttys3 <span class="token string">&quot;the-smb-password&quot;</span> /persistent:yes </span></code></pre></div><p><code>/persistent:yes</code> 确保配置持久保存,而<code>/user:ttys3</code> 是指定登录的用户名, 空格后面接的是密码。</p><p>基于安全考虑,也可以用一个单独的用户:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">useradd</span> <span class="token variable parameter">-M</span> <span class="token variable parameter">-s</span> /usr/sbin/nologin winshare </span><span class="code-line"><span class="token function">usermod</span> <span class="token variable parameter">--shell</span> /usr/sbin/nologin <span class="token variable parameter">--lock</span> winshare </span><span class="code-line">smbpasswd <span class="token variable parameter">-a</span> winshare </span><span class="code-line"><span class="token comment"># 然后设置密码(注意这里的密钥是用于设置samba用户的密码,新设置的,并不是要你输入系统用户的)</span> </span><span class="code-line"><span class="token function">sudo</span> systemctl restart smbd nmbd </span></code></pre></div><p>禁止ssh登录: 编辑 <code>/etc/ssh/sshd_config</code>, 修改或增加:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token maybe-class-name">AllowUsers</span> root ttys3 </span></code></pre></div><p>注意这里的<code>ttys3</code>是当前用户,<code>winshare</code>作为仅用于win guest访问共享的用户,被排除在了ssh登录之外。</p><p>如果是RHEL/CentOS/Fedora还要解决 selinux 问题:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">chcon <span class="token variable parameter">-t</span> public_content_rw_t /media/hdd/wd10t02/winshare </span><span class="code-line">setsebool <span class="token variable parameter">-P</span> <span class="token variable assign-left">allow_smbd_anon_write</span><span class="token operator">=</span><span class="token number">1</span> </span></code></pre></div><p>还有一种最简单的方法(允许匿名读写):</p><p>在<code>[global]</code>段添加:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">map to guest <span class="token operator">=</span> <span class="token maybe-class-name">Bad</span> <span class="token maybe-class-name">User</span> </span></code></pre></div><p>然后再在最后添加:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">winshare</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">comment</span><span class="token punctuation">=</span><span class="token attr-value value">share for kvm guest</span> </span><span class="code-line"><span class="token attr-name key">path</span><span class="token punctuation">=</span><span class="token attr-value value">/media/hdd/wd10t02/winshare</span> </span><span class="code-line"><span class="token attr-name key">browsable</span> <span class="token punctuation">=</span> <span class="token attr-value value">yes</span> </span><span class="code-line"><span class="token attr-name key">guest ok</span> <span class="token punctuation">=</span> <span class="token attr-value value">yes</span> </span><span class="code-line"><span class="token attr-name key">read only</span> <span class="token punctuation">=</span> <span class="token attr-value value">no</span> </span><span class="code-line"><span class="token attr-name key">hosts allow</span> <span class="token punctuation">=</span> <span class="token attr-value value">192.168.122.0/24</span> </span><span class="code-line"><span class="token attr-name key">create mask</span> <span class="token punctuation">=</span> <span class="token attr-value value">0777</span> </span><span class="code-line"><span class="token attr-name key">directory mask</span> <span class="token punctuation">=</span> <span class="token attr-value value">0777</span> </span></code></pre></div><p><code>192.168.122.0/24</code> 是 <code>virbr0</code> 的网段, 主要用来限制只允许guest机读写</p><h3 id="开发相关"><a href="#开发相关" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>开发相关</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> protobuf-compiler golang </span></code></pre></div><h3 id="grub配置调整"><a href="#grub配置调整" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>grub配置调整</h3><p>显示启动信息</p><p>How to enable boot messages to be printed on screen during boot up? Edit you bootloader kernel command-line and remove <code>quiet</code> argument. You may also want to remove <code>splash</code> argument to disable graphical animation during boot to be able to see the console with messages.</p><p>修改 <code>/etc/default/grub</code>, 找到 <code>GRUB_CMDLINE_LINUX</code> 一行,移除 <code>quiet</code> 和 <code>splash</code></p><p>更新grub配置:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">update-grub</span> </span></code></pre></div><h2 id="fucked-up"><a href="#fucked-up" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>fucked up</h2><p>各方面都没啥问题了。但是还是有一个问题, GNOME3 启动东西的时候总觉得有点卡的,然后执行<code>ps</code>看了下,内心是崩溃的。</p><p>执行<code>snap list</code>可查看被snap化的应用,其中包括:chromium !</p><p>core18 是 snap 应用的运行环境,而 snap-store 则是 ubuntu snap 应用商店, snapd 自然不用多说,是snap负责管理应用的daemon, 至于 gtk-common-themes, 只是为了使 snap 化的应用样式保持一致。</p><p><code>gnome-3-34-1804</code> 并不是 gnome (这里老灯之前误解了):</p><p>The gnome-3-34-1804 snap description is at snap info gnome-3-34-1804:</p><blockquote><p>This snap includes a GNOME 3.28 stack (the base libraries and desktop integration components) and shares it through the content interface.</p></blockquote><p>This means that your other gnome-based snaps connect to this snap in order to talk to Gnome. You can test this by removing the snap. Suddenly your other gnome-based snaps won&#x27;t work. Restore their function by re-installing the snap. (via <a href="https://askubuntu.com/questions/1231094/why-do-i-have-the-gnome-3-34-1804-snap-package-installed-on-ubuntu-20-04-after/1231100#1231100">https://askubuntu.com/questions/1231094/why-do-i-have-the-gnome-3-34-1804-snap-package-installed-on-ubuntu-20-04-after/1231100#1231100</a> )</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ snap list </span><span class="code-line">Name Version Rev Tracking Publisher Notes </span><span class="code-line">chromium <span class="token number">83.0</span>.4103.106 <span class="token number">1193</span> latest/stable canonical✓ - </span><span class="code-line">core18 <span class="token number">20200427</span> <span class="token number">1754</span> latest/stable canonical✓ base </span><span class="code-line">gnome-3-34-1804 <span class="token number">0</span>+git.3009fc7 <span class="token number">36</span> latest/stable/… canonical✓ - </span><span class="code-line">gtk-common-themes <span class="token number">0.1</span>-36-gc75f853 <span class="token number">1506</span> latest/stable/… canonical✓ - </span><span class="code-line">snap-store <span class="token number">3.36</span>.0-80-g208fd61 <span class="token number">467</span> latest/stable/… canonical✓ - </span><span class="code-line">snapd <span class="token number">2.45</span>.1 <span class="token number">8140</span> latest/stable canonical✓ snapd </span></code></pre></div><p>然后再看看 mount 的结果,你会发现这些应用居然是以<code>squashfs</code>文件系统打包的,然后解包就是一个将squashfs的文件挂载为一个loop设备:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">df</span> <span class="token variable parameter">-t</span> squashfs </span><span class="code-line">Filesystem 1K-blocks Used Available Use% Mounted on </span><span class="code-line">/dev/loop0 <span class="token number">56320</span> <span class="token number">56320</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/core18/1705 </span><span class="code-line">/dev/loop1 <span class="token number">63616</span> <span class="token number">63616</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/gtk-common-themes/1506 </span><span class="code-line">/dev/loop2 <span class="token number">246656</span> <span class="token number">246656</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/gnome-3-34-1804/24 </span><span class="code-line">/dev/loop4 <span class="token number">27776</span> <span class="token number">27776</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/snapd/7264 </span><span class="code-line">/dev/loop3 <span class="token number">51072</span> <span class="token number">51072</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/snap-store/433 </span><span class="code-line">/dev/loop5 <span class="token number">56320</span> <span class="token number">56320</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/core18/1754 </span><span class="code-line">/dev/loop6 <span class="token number">30592</span> <span class="token number">30592</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/snapd/8140 </span><span class="code-line">/dev/loop7 <span class="token number">51072</span> <span class="token number">51072</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/snap-store/467 </span><span class="code-line">/dev/loop8 <span class="token number">261760</span> <span class="token number">261760</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/gnome-3-34-1804/36 </span><span class="code-line">/dev/loop9 <span class="token number">160000</span> <span class="token number">160000</span> <span class="token number">0</span> <span class="token number">100</span>% /snap/chromium/1193 </span></code></pre></div><div><img alt="snap-list.jpg" src="https://ttys3.dev/static/assets/snap-list-XAC2MMQL.jpg" width="800" height="435"/></div><p>Ubuntu的默认浏览器是 Firefox , 然而很多用户或者开发者,可能都离不开 chromium (即使它不是默认浏览器),而 Ubuntu 将 <code>chromium-browser</code> 强制 snap 化, 等于是强制用户使用 snap 了 (Ubuntu的阴谋)。</p><p>snap后的程序有两大问题:</p><ul><li>一是慢,虽然Ubuntu官方宣称 snap 速度已经相比之前提升了几倍,但是,老灯同时在用Fedora 32, 所有程序打开流畅无比。但是 Ubuntu 20.04 下启动或关闭程序一些程序是能感受到明显的卡顿。这个卡顿在1秒以上。</li><li>二是体积大。其打包的app体积,相比于AppImage 或 Flatpak, 也是大很多。以Corebird这个应用为例,snap 112MB, deb 2MB, Flatpak 12MB (参考 <a href="https://www.omgubuntu.co.uk/2017/08/bug-report-asks-why-snappy">Snappy Sceptic Files Bug to Ask Why It Even Exists</a> 一文).</li></ul><p>另外, GNOME 软件中心,被 Ubuntu 偷偷替换成了 snap store! 这意味着用户要是从默认的这个所谓的“软件中心”安装任何应用,这个应用都是 snap 的!</p><p>相比于 Fedora 带的软件中心,用户默认是安装 rpm 源的应用,如果有些应用只有 Flatpak 的才会用的 Flatpak 源。</p><p>所以 Ubuntu 的意图很明显,就是经强推 snap store !</p><p>查了下, 老灯不是唯一一个不喜欢snap的,事实上, 很多人或团队都在对snap说“NO”:</p><p>Linux Mint 团队认为 Ubuntu 偷梁换柱把默认的 GNOME Software 换成了 Ubuntu store, 把 <code>chromium-browser</code> deb 包换成了一个空包(然后替换成了下载snap版的chromium), 这是一个“后门”行为。没有任何说明,Ubuntu 就直接这么干了。</p><blockquote><p>Mint gets fresh: &#x27;A self-installing Snap Store which overwrites part of our APT package base is a complete NO NO&#x27;</p></blockquote><blockquote><p>&quot;I don&#x27;t think the points we&#x27;re raising here are well understood by the community. I hope we&#x27;ll talk with Ubuntu and the Snap project about this. We&#x27;re very interested in your feedback as well. A self-installing Snap Store which overwrites part of our APT package base is a complete NO NO. It&#x27;s something we have to stop and it could mean the end of Chromium updates and access to the snap store in Linux Mint.&quot;</p></blockquote><p>更多信息可查看 <a href="https://www.theregister.com/2020/06/02/linux_mint_team_snap/">Snapping at Canonical&#x27;s Snap: Linux Mint team says no to Ubuntu store &#x27;backdoor&#x27;</a></p><p>和 <a href="https://blog.linuxmint.com/?p=3906">https://blog.linuxmint.com/?p=3906</a></p><p><a href="https://news.slashdot.org/story/20/06/05/2148219/linux-mint-dumps-ubuntu-snap">Linux Mint Dumps Ubuntu Snap</a></p><p>另外一部分用户则觉得自己被 fucked up 了:</p><p><a href="https://www.reddit.com/r/Ubuntu/comments/g9c2t6/i_think_i_fucked_up/">I think I fucked up?</a></p><p>有人甚至觉得这是一个bug: <a href="https://www.omgubuntu.co.uk/2017/08/bug-report-asks-why-snappy">Snappy Sceptic Files Bug to Ask Why It Even Exists</a></p><p>还有人写了如何在Ubuntu 20.04禁用snap(完全卸载snap相关组件)的教程:</p><p><a href="https://www.kevin-custer.com/blog/disabling-snaps-in-ubuntu-20-04/">Disabling Snaps in Ubuntu 20.04</a> 相应的讨论 <a href="https://news.ycombinator.com/item?id=22972661">https://news.ycombinator.com/item?id=22972661</a></p><p><a href="https://jatan.blog/2020/05/02/ubuntu-snap-obsession-has-snapped-me-off-of-it/">Ubuntu 20.04 LTS’ snap obsession has snapped me off of it</a> 相应的讨论 <a href="https://news.ycombinator.com/item?id=23052108">https://news.ycombinator.com/item?id=23052108</a></p><p><a href="https://jatan.blog/2020/04/25/how-to-install-flatpak-apps-on-ubuntu-20-04-lts/">How to install Flatpak apps on Ubuntu 20.04 LTS</a></p><p>Von Goofy 评论道(<a href="https://www.omgubuntu.co.uk/2020/02/ubuntu-snap-store-transition">Ubuntu Switches to a Snap’d Software Store for 20.04</a>):</p><blockquote><p>We don&#x27;t buy SSD&#x27;s and computers with SSD&#x27;s to be reverted to HDD speeds by some devs that think packaging apps and dependencies together is a cool idea no matter how slow it is. No, I don&#x27;t want for basic calculator to have a startup time of 15 seconds. That is not acceptable in 2020. Not on a desktop and not with desktop apps. The idea is valid and good, the execution is poor. I understand that devs might find this very useful, but stop pushing it by default for regular users. Until the issue of speed and themes are resolved this is still beta software that shouldn&#x27;t be in main stream distributions.</p></blockquote><p>其它文章:</p><p><a href="https://www.howtogeek.com/670084/what-you-need-to-know-about-snaps-on-ubuntu-20.04/">What You Need to Know About Snaps on Ubuntu 20.04</a></p><p><a href="https://thenewstack.io/canonicals-snap-great-good-bad-ugly/">Canonical’s Snap: The Good, the Bad and the Ugly</a></p><h2 id="troubleshoot"><a href="#troubleshoot" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>troubleshoot</h2><ol><li>Although GNOME Shell integration extension is running, native host connector is not detected</li></ol><p>解决办法(来自 <a href="https://askubuntu.com/questions/1107848/although-gnome-shell-integration-extension-is-running-native-host-connector-is">https://askubuntu.com/questions/1107848/although-gnome-shell-integration-extension-is-running-native-host-connector-is</a> ):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> update </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> upgrade </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> chrome-gnome-shell </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Ubuntu 20.04</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> libproxy1-plugin-networkmanager gnome-shell-extension-system-monitor </span></code></pre></div><p>常用扩展安装:</p><p>fmuellner 的一些扩展(Window List是老灯必装) <a href="https://extensions.gnome.org/accounts/profile/fmuellner">https://extensions.gnome.org/accounts/profile/fmuellner</a></p><p>KStatusNotifierItem/AppIndicator Support by 3v1n0 <a href="https://extensions.gnome.org/extension/615/appindicator-support/">https://extensions.gnome.org/extension/615/appindicator-support/</a></p><ol start="2"><li>左边 Dock 自动隐藏(像原版GNOME3那样)</li></ol><p>Settings - Appearance - Dock - Auto-hide the dock</p><ol start="3"><li>卸载Ubuntu使用的一些旧组件</li></ol><p>一些组件,GNOME 3已经有自带了,Ubuntu并没有使用。</p><p><a href="https://www.omgubuntu.co.uk/2020/02/gnome-3-36-features#software-swaps">GNOME 3.36: The 10 Best New Features</a>这篇文章有介绍:</p><blockquote><p>GNOME’s recommended roster of default apps — which most Linux distros do not ship or heed, including Ubuntu — sees a number of <a href="https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/907">notable substitutions</a>:</p></blockquote><ul><li>Shotwell replaced by GNOME Photos</li><li>Evolution replaced by Geary &amp; GNOME Calendar</li><li>Rhythmbox replaced by GNOME Music</li></ul><p>GNOME 的代码<a href="https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/907">commit信息中有写原因</a>:</p><blockquote><p>Many of the apps in the favorite apps list have fallen out of favor.</p><p>Replacing <strong>Rhythmbox</strong> with <strong>Music</strong> and <strong>Shotwell</strong> with <strong>Photos</strong> are obvious moves. Rhythmbox and Shotwell are not core apps, and that means we assume they are not installed by default. It doesn&#x27;t really make sense to have non-default apps in the apps list.</p><p><strong>Evolution</strong> is also not a core app, and that is not likely to change, so it should also be removed. Adding <strong>Geary</strong> might be more controversial. It is a strong candidate to become a core app, GNOME Mail, in the near future, but it is not there yet. So this could arguably be considered premature. But I figure a GSettings default is a cheap thing; we can always change it later if desired.</p></blockquote><p>邮件客户端: 卸载thunderbird, 安装geary</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> remove thunderbird </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> geary </span></code></pre></div><p>照片管理: uninstall <a href="https://wiki.gnome.org/Apps/Shotwell">Shotwell</a> , install <a href="https://wiki.gnome.org/Apps/Photos">gnome-photos</a> (Fedora 32的默认应用)</p><p>GNOME3 默认的图片查看器(viewer)是 <a href="https://wiki.gnome.org/Apps/EyeOfGnome">Eye of GNOME (eog)</a>, 如果需要查看exiv信息,可以安装<a href="https://wiki.gnome.org/Apps/Gthumb">gThumb</a>, 而老灯用过的打开图片速度最快的是 <a href="https://github.com/easymodo/qimgv">qimgv</a>。</p><p>但是这里说的是图片管理器,并不是查看器(viewer)。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> remove shorewell </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> gnome-photos </span></code></pre></div><p>tips: 如果要查看已经安装了哪些package, 可以用 <code>apt list --installed</code></p><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://blog.programster.org/kvm-missing-default-network">https://blog.programster.org/kvm-missing-default-network</a></p><p><a href="https://wiki.archlinux.org/index.php/Samba#User_Management">https://wiki.archlinux.org/index.php/Samba#User_Management</a></p><p><a href="https://wiki.archlinux.org/index.php/Users_and_groups#User_management">https://wiki.archlinux.org/index.php/Users_and_groups#User_management</a></p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_virtualization/sharing-files-between-the-host-and-its-virtual-machines_configuring-and-managing-virtualization#sharing-files-between-the-host-and-windows-virtual-machines_sharing-files-between-the-host-and-its-virtual-machines">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_virtualization/sharing-files-between-the-host-and-its-virtual-machines_configuring-and-managing-virtualization#sharing-files-between-the-host-and-windows-virtual-machines_sharing-files-between-the-host-and-its-virtual-machines</a></p><p><a href="https://blog.linuxmint.com/?p=3906">https://blog.linuxmint.com/?p=3906</a></p> Thu, 25 Jun 2020 10:35:25 GMT ttyS3 ubuntusnapchromiumsquashfsfucked upWTF https://ttys3.dev/blog/golang中使用defer时注意io缓冲区刷新问题 Golang中使用defer时注意io缓冲区刷新问题 https://ttys3.dev/blog/golang中使用defer时注意io缓冲区刷新问题 <p>关于<code>defer</code> Golang 官方博客专门发文<a href="https://blog.golang.org/defer-panic-and-recover">介绍过三条规则</a>:</p><blockquote><ol><li>defer语句被求值时,被defer调用的函数参数即时求值 A deferred function&#x27;s arguments are evaluated when the defer statement is evaluated.</li></ol></blockquote><p><code>Defer statements</code>的<a href="https://golang.org/ref/spec#Defer_statements">Spec</a>中有这么一句描述:</p><blockquote><p>Each time a &quot;defer&quot; statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.</p></blockquote><p>&quot;defer&quot; statement 的定义为:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line">DeferStmt <span class="token operator">=</span> <span class="token string">&quot;defer&quot;</span> Expression <span class="token punctuation">.</span> </span></code></pre></div><p>举例:</p><ul><li><code>defer f(&quot;a&quot;)</code>, the function value = <code>f</code>, the parameters = <code>&quot;a&quot;</code></li><li><code>defer f(g(&quot;a&quot;))</code>, the function value = <code>f</code>, the parameters = <code>g(&quot;a&quot;)</code>, <code>g(&quot;a&quot;)</code> 会被马上求值</li><li><code>defer f()()</code>,the function value = <code>f()</code>, no parameters, <code>f()</code>会被马上求值</li></ul><p>关于这个第一点,应该是日常使用中需要注意比较多的,比如:</p><p>以下程序中, <code>defer</code>调用的结果为输出<code>0s</code>, 原因在于<code>time.Since(startedAt)</code>作为<code>fmt.Println</code>的参数,会被即时求值,而不是延迟到defer语句真正执行的时候。</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> startedAt <span class="token operator">:=</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">defer</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span><span class="token function">Since</span><span class="token punctuation">(</span>startedAt<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// bug: time.Since(startedAt) 被即时求值</span> </span><span class="code-line"> </span><span class="code-line"> time<span class="token punctuation">.</span><span class="token function">Sleep</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>Second<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>修正方法为采用闭包: <code>defer func() { fmt.Println(time.Since(startedAt)) }()</code>。</p><p>以下程序中, <code>defer</code>调用的结果为输出<code>Giney</code>, 而不是 <code>Hermionie</code>, 虽然传递的参数是指针,但是Golang为按值传递,因此在给defer调用的函数的参数求值时, 实际上指针的地址就已经确定了。</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token punctuation">(</span> </span><span class="code-line"> <span class="token string">&quot;fmt&quot;</span> </span><span class="code-line"><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">type</span> Data <span class="token keyword">struct</span> <span class="token punctuation">{</span> </span><span class="code-line"> name <span class="token builtin">string</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token punctuation">(</span>d Data<span class="token punctuation">)</span> <span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> fmt<span class="token punctuation">.</span><span class="token function">Sprintf</span><span class="token punctuation">(</span><span class="token string">&quot;Name: %s&quot;</span><span class="token punctuation">,</span> d<span class="token punctuation">.</span>name<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> ss <span class="token operator">:=</span> <span class="token operator">&amp;</span>Data<span class="token punctuation">{</span><span class="token string">&quot;Giney&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword">defer</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>ss <span class="token operator">*</span>Data<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>ss<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">(</span>ss<span class="token punctuation">)</span> </span><span class="code-line"> ss <span class="token operator">=</span> <span class="token operator">&amp;</span>Data<span class="token punctuation">{</span><span class="token string">&quot;Hermionie&quot;</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token comment">//ss.name = &quot;Hermionie&quot;</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>ss<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"><span class="token comment">//result:</span> </span><span class="code-line"><span class="token comment">// Name: Hermionie</span> </span><span class="code-line"><span class="token comment">// Name: Giney</span> </span></code></pre></div><blockquote><ol start="2"><li>被defer调用的函数,以后进先出的顺序执行 Deferred function calls are executed in Last In First Out order after the surrounding function returns.</li></ol></blockquote><blockquote><ol start="3"><li>被defer调用的函数可读取或修改即将返回到的函数的命名返回值 Deferred functions may read and assign to the returning function&#x27;s named return values.</li></ol></blockquote><p>然而今天老灯要分享的这个问题跟上面三点都无关。</p><p>这个问题来自一个<a href="https://github.com/umputun/remark42/commit/200f464925dcebd8e22b078d50c460fd28e3a115#diff-b5a3982d2e4e856944cb712a6d9bd677">真实的案例</a>。</p><p>原来的代码如下:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// buildMessage generates email message to send using net/smtp.Data()</span> </span><span class="code-line"><span class="token keyword">func</span> <span class="token punctuation">(</span>e <span class="token operator">*</span>Email<span class="token punctuation">)</span> <span class="token function">buildMessage</span><span class="token punctuation">(</span>subject<span class="token punctuation">,</span> body<span class="token punctuation">,</span> to<span class="token punctuation">,</span> contentType<span class="token punctuation">,</span> unsubscribeLink <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">(</span>message <span class="token builtin">string</span><span class="token punctuation">,</span> err <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">//省略无关部分代码 ...</span> </span><span class="code-line"> </span><span class="code-line"> message <span class="token operator">=</span> <span class="token function">addHeader</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> <span class="token string">&quot;Date&quot;</span><span class="token punctuation">,</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Format</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>RFC1123Z<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> buff <span class="token operator">:=</span> <span class="token operator">&amp;</span>bytes<span class="token punctuation">.</span>Buffer<span class="token punctuation">{</span><span class="token punctuation">}</span> </span><span class="code-line"> qp <span class="token operator">:=</span> quotedprintable<span class="token punctuation">.</span><span class="token function">NewWriter</span><span class="token punctuation">(</span>buff<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token boolean">_</span><span class="token punctuation">,</span> err <span class="token operator">:=</span> qp<span class="token punctuation">.</span><span class="token function">Write</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token function">byte</span><span class="token punctuation">(</span>body<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">,</span> err </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword">defer</span> qp<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> m <span class="token operator">:=</span> buff<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> message <span class="token operator">+=</span> <span class="token string">&quot;\n&quot;</span> <span class="token operator">+</span> m </span><span class="code-line"> <span class="token keyword">return</span> message<span class="token punctuation">,</span> <span class="token boolean">nil</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>这个方法的主要作用,除了给email添加必要的头部,其次就是调用 <code>quotedprintable</code>将原始的body编码成遵循RFC 2045规范的quoted-printable编码。 新建一空的buff作为writer, 然后输入body进行编码,然后为了正常关闭quotedprintable writer, 这里用到了<code>defer qp.Close()</code>。 看上去好像没啥问题。但是老灯在测试的时候,发现有时候,返回的邮件 message 的 body是空的。后面进一步调试,发现在 body 文本的内容非常短小的时候, 很大概率可重现这个bug.</p><p>那么,产生bug的原因是什么呢?就在于这个<code>defer qp.Close()</code></p><p>虽然<code>defer</code>能确保qp能在方法return message之前执行,但此时已经为时已晚了。因为在return之前,<code>message</code>的值已经被计算过了。而此时<code>buff.String()</code>取到的, 很可能是没有刷新的一个buffer, 因此在body内容非常短小的时候,可能整个值都还在缓冲区里,因此最终导致<code>buff.String()</code>获得的值为空。</p><p>我们看一下quotedprintable 的 writer <code>Close()</code>的<a href="https://golang.org/src/mime/quotedprintable/writer.go?s=1499:1529#L57">实现</a>:</p><div class="relative"><pre><code class="language-go code-highlight"><span class="code-line"><span class="token comment">// Close closes the Writer, flushing any unwritten data to the underlying</span> </span><span class="code-line"><span class="token comment">// io.Writer, but does not close the underlying io.Writer.</span> </span><span class="code-line"><span class="token keyword">func</span> <span class="token punctuation">(</span>w <span class="token operator">*</span>Writer<span class="token punctuation">)</span> <span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> err <span class="token operator">:=</span> w<span class="token punctuation">.</span><span class="token function">checkLastByte</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">return</span> err </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">return</span> w<span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>由于<code>Close()</code> 隐式地调用了<code>w.flush()</code>,因此,如果我们要用到write写入的东西完整内容,必须要先调用<code>Close()</code> 来促使writer刷新缓冲区。</p><p>修复方式当然也很简单,将<code>defer qp.Close()</code>换成显式的<code>qp.Close()</code>调用即可,同时注意检查错误。</p><div><img alt="" src="https://ttys3.dev/static/assets/qp-explicit-call-to-Cloase-2020-06-22-22-07-37-W3V5ZD2K.png" width="1962" height="458"/></div><p>参考文档:</p><p><a href="https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-defer/">https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-defer/</a></p><p><a href="https://medium.com/@manandharsabbir/go-lang-defer-statement-arguments-evaluated-at-defer-execution-b2c4a1687c6c">https://medium.com/@manandharsabbir/go-lang-defer-statement-arguments-evaluated-at-defer-execution-b2c4a1687c6c</a></p><p><a href="https://stackoverflow.com/questions/51360229/the-deferred-calls-arguments-are-evaluated-immediately">https://stackoverflow.com/questions/51360229/the-deferred-calls-arguments-are-evaluated-immediately</a></p><p><a href="https://blog.golang.org/defer-panic-and-recover">https://blog.golang.org/defer-panic-and-recover</a></p><p><a href="https://golang.org/ref/spec#Defer_statements">https://golang.org/ref/spec#Defer_statements</a></p> Mon, 22 Jun 2020 11:59:27 GMT ttyS3 golangdefer https://ttys3.dev/blog/调整了一下terminal主题 调整了一下terminal主题 https://ttys3.dev/blog/调整了一下terminal主题 <p>有人看过我的博客后觉得主题的配色有些过于闪亮。 而<code>terminal</code>这个主题里,我选取的还是唯一不那么“闪”的<code>orange</code>颜色。于是我按自己的想法,调整了一下默认<code>orange</code>方案的配色。 现在博客应该看起来舒服一些了。</p><div><img alt="hugo-terminal-theme-orig-color.png" src="https://ttys3.dev/static/assets/hugo-terminal-theme-orig-color-OZ25VI26.png" width="1500" height="1000"/></div><p>同时,顶部加上了一个小banner背景图, 毕竟一个博客没有一张图片,也略显单调。</p><p>刚好前面了解到一个免费图片素材网站(无需版权,免费商用), 搜索了下<a href="https://pixabay.com/photos/search/black%20and%20white/?orientation=horizontal">黑白主题</a> 的图片,找到一个比较合心意的: <a href="https://pixabay.com/photos/leaf-web-black-white-yellow-sheet-1571833/">https://pixabay.com/photos/leaf-web-black-white-yellow-sheet-1571833/</a></p><div><img alt="leaf-1571833_1920.jpg" src="https://ttys3.dev/static/assets/leaf-1571833_1920-B76MNPL3.jpg" width="1920" height="1440"/></div><p>修改之后效果:</p><div><img alt="terminal-theme-mod-2020-06-22.png" src="https://ttys3.dev/static/assets/terminal-theme-mod-2020-06-22-HY4APXFC.png" width="2340" height="1736"/></div> Mon, 22 Jun 2020 11:39:03 GMT ttyS3 hugo https://ttys3.dev/blog/does-qbittorrent-directory-watch-support-ntfs qBittorrent目录监视功能在Linux下是否支持NTFS文件系统? https://ttys3.dev/blog/does-qbittorrent-directory-watch-support-ntfs <p>English title: Does qBittorrent Directory Watch Support NTFS?</p><p><a href="https://github.com/qbittorrent/qBittorrent">qBittorrent</a> 是一个基于<a href="https://github.com/arvidn/libtorrent">rb_libtorrent库</a> 的跨平台高性能BT客户端。</p><p>这个<code>libtorrent</code> 有一个前缀<code>rb_</code>的原因是,有一个叫做<a href="https://github.com/rakshasa/rtorrent">RTorrent</a>的软件已经占用了<code>libtorrent</code>这个名字。</p><p>而在qB和Deluge里面,通常大家所说的<code>libtorrent</code> ,全名是<code>libtorrent-rasterbar</code>, 也就是 RHEL包名里的<code>rb_libtorrent</code></p><h2 id="缘由"><a href="#缘由" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h2><p>今天有群友说qB的目录监视功能对于NTFS文件系统下的目录不工作,然后我回复说, Linux下的inotify是无法支持NTFS文件系统的,并建议其更换为EXT4文件系统。 然后有群友反馈说,根据他的使用经验,qB Linux版对于NTFS文件的watch功能一直是工作正常的。当然,一开始我对此是表示怀疑的,但是此群友随即截图表示,测试了下,再次确认是工作的。</p><p>(先说下结果: 后面我也确认了,qBittorrent目录监视功能在Linux下是支持NTFS文件系统的, 那位监视功能不工作的群友,应该是配置不正确导致的)</p><p>当然,在此之前我并没有看过qB关于这一块的代码。于是我决定花些时间一探究竟。</p><h2 id="qb的种子目录监视功能实现分析"><a href="#qb的种子目录监视功能实现分析" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>qB的种子目录监视功能实现分析</h2><p>qB是基于 qt5 开发的,而 qt5 的文件监视功能主要是由 <a href="https://doc.qt.io/qt-5/qfilesystemwatcher.html">QFileSystemWatcher</a> 实现。</p><p>于是我又查看了一下<code>QFileSystemWatcher</code>的源码相关实现 <a href="https://github.com/qt/qtbase/blob/69795835f3a578f60b16f09943feee6326087342/src/corelib/io/qfilesystemwatcher.cpp#L50">https://github.com/qt/qtbase/blob/69795835f3a578f60b16f09943feee6326087342/src/corelib/io/qfilesystemwatcher.cpp#L50</a> , 确认了在Linux下,<code>QFileSystemWatcher</code>实际上是基于<code>inotify</code>来实现的。</p><p>老灯没有看到任何文档表明<code>inotify</code>支持NTFS文件系统(荒野注:后续的测试表明,这个猜想是错误的。), 因为 libinotify 主要是基于<code>inode</code> 工作的, NTFS 并不存在 <code>inode</code> 这一概念。 同时这里有个类似的回复刚好证实老灯的猜测: <a href="https://bugs.launchpad.net/drapes/+bug/110117">https://bugs.launchpad.net/drapes/+bug/110117</a></p><div><img alt="" src="https://ttys3.dev/static/assets/inotify-on-ntfs-2020-06-08-14-34-24-DRNRMYVH.png" width="1338" height="465"/></div><p>既然 qt5 在 Linux 下是肯定不能 watch NTFS 文件系统的,那么我想 qB 肯定是采用了其它实现。(荒野注:后续的测试表明,这个猜想是错误的。)</p><p>很快定位到 qB 的相关源码 <code>src/base/filesystemwatcher.cpp</code> 和 <code>src/base/filesystemwatcher.h</code></p><p>我们看一下添加监视目录的相关实现:</p><div class="relative"><pre><code class="code-highlight language-cpp"><span class="code-line"><span class="token keyword">namespace</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// 监视定时器 间隔时间, 10秒(同时用于 网络文件系统 和 不完整种子 ,注意本地文件系统用的是singleShot, 并且间隔固定为2秒)</span> </span><span class="code-line"> <span class="token keyword">const</span> <span class="token keyword">int</span> WATCH_INTERVAL <span class="token operator">=</span> <span class="token number">10000</span><span class="token punctuation">;</span> <span class="token comment">// 10 sec</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 不完整种子 检测次数限制, 超过5次</span> </span><span class="code-line"> <span class="token keyword">const</span> <span class="token keyword">int</span> MAX_PARTIAL_RETRIES <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// 首先`FileSystemWatcher` 是继承自 `QFileSystemWatcher`的</span> </span><span class="code-line"><span class="token class-name">FileSystemWatcher</span><span class="token punctuation double-colon">::</span><span class="token function">FileSystemWatcher</span><span class="token punctuation">(</span>QObject <span class="token operator">*</span>parent<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token operator">:</span> <span class="token function">QFileSystemWatcher</span><span class="token punctuation">(</span>parent<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// 来自 QFileSystemWatcher 的事件通知,当目录有变动时, 执行 scanLocalFolder</span> </span><span class="code-line"> <span class="token function">connect</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>QFileSystemWatcher<span class="token punctuation double-colon">::</span>directoryChanged<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>FileSystemWatcher<span class="token punctuation double-colon">::</span>scanLocalFolder<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// m_partialTorrentTimer 定时器用于处理“不完整种子”(主要的场景是,一个种子比较大,刚好在copy的时候被发现了,但是此时种子还没有write完)</span> </span><span class="code-line"> <span class="token comment">// 将 m_partialTorrentTimer 设置成single-shot timer, 这种定时器只会fire一次</span> </span><span class="code-line"> m_partialTorrentTimer<span class="token punctuation">.</span><span class="token function">setSingleShot</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">connect</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>m_partialTorrentTimer<span class="token punctuation">,</span> <span class="token operator">&amp;</span>QTimer<span class="token punctuation double-colon">::</span>timeout<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>FileSystemWatcher<span class="token punctuation double-colon">::</span>processPartialTorrents<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// m_watchTimer 用于处理网络文件系统(比如nfs之类的)下的目录监视, 这个QTimer是会不断定时触发的(每10秒)</span> </span><span class="code-line"> <span class="token function">connect</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>m_watchTimer<span class="token punctuation">,</span> <span class="token operator">&amp;</span>QTimer<span class="token punctuation double-colon">::</span>timeout<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>FileSystemWatcher<span class="token punctuation double-colon">::</span>scanNetworkFolders<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">void</span> <span class="token class-name">FileSystemWatcher</span><span class="token punctuation double-colon">::</span><span class="token function">addPath</span><span class="token punctuation">(</span><span class="token keyword">const</span> QString <span class="token operator">&amp;</span>path<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// Q_OS_HAIKU 这个咱也不用管,没怎么听过的操作系统。</span> </span><span class="code-line"> <span class="token comment">// 由于我们这里讨论的是 Linux 系统,因此可以忽视这个 macro .</span> </span><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">if</span> <span class="token expression"><span class="token operator">!</span>defined Q_OS_HAIKU</span></span> </span><span class="code-line"> <span class="token keyword">const</span> QDir <span class="token function">dir</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// 目录不存在则直接返回</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>dir<span class="token punctuation">.</span><span class="token function">exists</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 针对网络文件系统处理</span> </span><span class="code-line"> <span class="token comment">// Check if the path points to a network file system or not</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span>Utils<span class="token punctuation double-colon">::</span><span class="token class-name">Fs</span><span class="token punctuation double-colon">::</span><span class="token function">isNetworkFileSystem</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// Network mode</span> </span><span class="code-line"> <span class="token function">LogMsg</span><span class="token punctuation">(</span><span class="token function">tr</span><span class="token punctuation">(</span><span class="token string">&quot;Watching remote folder: \&quot;%1\&quot;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">arg</span><span class="token punctuation">(</span>Utils<span class="token punctuation double-colon">::</span><span class="token class-name">Fs</span><span class="token punctuation double-colon">::</span><span class="token function">toNativePath</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> m_watchedFolders <span class="token operator">&lt;&lt;</span> dir<span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 新目录加入watch列表后,马上 启动 或 重启 timer</span> </span><span class="code-line"> m_watchTimer<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span>WATCH_INTERVAL<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 返回</span> </span><span class="code-line"> <span class="token keyword">return</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">endif</span></span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 正常模式,针对本地文件系统</span> </span><span class="code-line"> <span class="token comment">// Normal mode</span> </span><span class="code-line"> <span class="token function">LogMsg</span><span class="token punctuation">(</span><span class="token function">tr</span><span class="token punctuation">(</span><span class="token string">&quot;Watching local folder: \&quot;%1\&quot;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">arg</span><span class="token punctuation">(</span>Utils<span class="token punctuation double-colon">::</span><span class="token class-name">Fs</span><span class="token punctuation double-colon">::</span><span class="token function">toNativePath</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 注意这里的addPath是QFileSystemWatcher的,因此,对于NTFS肯定是不生效</span> </span><span class="code-line"> <span class="token class-name">QFileSystemWatcher</span><span class="token punctuation double-colon">::</span><span class="token function">addPath</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 调用 scanLocalFolder 进行处理</span> </span><span class="code-line"> <span class="token function">scanLocalFolder</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>我们再看一下<code>scanLocalFolder</code>的实现:</p><div class="relative"><pre><code class="code-highlight language-cpp"><span class="code-line"><span class="token keyword">void</span> <span class="token class-name">FileSystemWatcher</span><span class="token punctuation double-colon">::</span><span class="token function">scanLocalFolder</span><span class="token punctuation">(</span><span class="token keyword">const</span> QString <span class="token operator">&amp;</span>path<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// 直接启动一个single-shot timer, 这种定时器只会fire一次,时间为 2秒 种之后</span> </span><span class="code-line"> <span class="token class-name">QTimer</span><span class="token punctuation double-colon">::</span><span class="token function">singleShot</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">,</span> path<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">processTorrentsInDir</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>然后我们再看 <code>processTorrentsInDir</code> 的实现:</p><div class="relative"><pre><code class="code-highlight language-cpp"><span class="code-line"><span class="token keyword">void</span> <span class="token class-name">FileSystemWatcher</span><span class="token punctuation double-colon">::</span><span class="token function">processTorrentsInDir</span><span class="token punctuation">(</span><span class="token keyword">const</span> QDir <span class="token operator">&amp;</span>dir<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> QStringList torrents<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">const</span> QStringList files <span class="token operator">=</span> dir<span class="token punctuation">.</span><span class="token function">entryList</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">&quot;*.torrent&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;*.magnet&quot;</span><span class="token punctuation">}</span><span class="token punctuation">,</span> QDir<span class="token punctuation double-colon">::</span>Files<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> QString <span class="token operator">&amp;</span>file <span class="token operator">:</span> files<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">const</span> QString fileAbsPath <span class="token operator">=</span> dir<span class="token punctuation">.</span><span class="token function">absoluteFilePath</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// .magnet 后缀的文件,主要是用于 Vuze 客户端的一种文件格式</span> </span><span class="code-line"> <span class="token comment">// 对于 qB 或 transmission 用户来说,基本上不太可能遇到这种文件</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span>file<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">&quot;.magnet&quot;</span><span class="token punctuation">,</span> Qt<span class="token punctuation double-colon">::</span>CaseInsensitive<span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> torrents <span class="token operator">&lt;&lt;</span> fileAbsPath<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>BitTorrent<span class="token punctuation double-colon">::</span><span class="token class-name">TorrentInfo</span><span class="token punctuation double-colon">::</span><span class="token function">loadFromFile</span><span class="token punctuation">(</span>fileAbsPath<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isValid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 对于 .torrent 后缀的文件,加载并判断合法性</span> </span><span class="code-line"> torrents <span class="token operator">&lt;&lt;</span> fileAbsPath<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>m_partialTorrents<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span>fileAbsPath<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 不是合法的torrent文件,程序认为它是一个局部种子文件,即不完整的,主要原因是考虑到io速度,这个文件可能还没有写完就在读取了</span> </span><span class="code-line"> m_partialTorrents<span class="token punctuation">[</span>fileAbsPath<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">// 局部文件,添加到 m_partialTorrents 这个 hash表,key 为路径,value为检测次数</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 找到种子了(不管是新是旧), fire 一个 torrentsAdded 信号, 然后qB另外部分的代码收到这个信号,就会开始新种子下载了</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>torrents<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> emit <span class="token function">torrentsAdded</span><span class="token punctuation">(</span>torrents<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// 如果局部种子hash表非空 并且 m_partialTorrentTimer 定时器 是非活跃 not running (pending), 则启动一个定时器</span> </span><span class="code-line"> <span class="token comment">// 之所以要启动,前面我们已经分析过了,m_partialTorrentTimer 在构造方法里,被设置成了 single-shot timer</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>m_partialTorrents<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>m_partialTorrentTimer<span class="token punctuation">.</span><span class="token function">isActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> </span><span class="code-line"> m_partialTorrentTimer<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span>WATCH_INTERVAL<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>所以,在不存在“局部种子”的情况下, 本地文件系统下的被 watch 的目录,只会在qB添加这个目录的时候被扫描一次,后续的任务都交给了<code>QFileSystemWatcher::directoryChanged</code>信号。 收到这个信号就会重新扫描一次被 watch 的目录。</p><p>所以, qB 并没有做其它特殊的处理,它完全依赖 QFileSystemWatcher 本身的机制 (而 QFileSystemWatcher 又是依赖 inotify )。</p><p>然而,事情的真相真的是这样么?</p><p>我基于<a href="https://gist.github.com/iamAzeem/0f690c039660f7b16ad43c2e7f31d71e">一个gist</a> 修改了下,做了一个简单的测试demo。</p><p>代码仓库在这 <a href="https://github.com/ttys3/qt_directory_watcher">https://github.com/ttys3/qt_directory_watcher</a></p><p><code>watcher.pro</code> 文件内容如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment">#-------------------------------------------------</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># Project created by QtCreator 2020-06-08T16:24:38</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment">#-------------------------------------------------</span> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">QT +</span><span class="token punctuation">=</span> <span class="token attr-value value">core widgets</span> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">QT -</span><span class="token punctuation">=</span> <span class="token attr-value value">gui</span> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">TARGET</span> <span class="token punctuation">=</span> <span class="token attr-value value">watcher</span> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">CONFIG +</span><span class="token punctuation">=</span> <span class="token attr-value value">console</span> </span><span class="code-line"><span class="token attr-name key">CONFIG -</span><span class="token punctuation">=</span> <span class="token attr-value value">app_bundle</span> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">TEMPLATE</span> <span class="token punctuation">=</span> <span class="token attr-value value">app</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token attr-name key">SOURCES +</span><span class="token punctuation">=</span> <span class="token attr-value value">qt_directory_watcher.cpp</span> </span></code></pre></div><p><code>qt_directory_watcher.cpp</code> 内容如下:</p><div class="relative"><pre><code class="code-highlight language-cpp"><span class="code-line"><span class="token comment">// ----------------------------------------------</span> </span><span class="code-line"><span class="token comment">// List the contents of a directory if changed</span> </span><span class="code-line"><span class="token comment">// Using QFileSystemWatcher, QDirIterator and</span> </span><span class="code-line"><span class="token comment">// QEventLoop, and lambda function for connect</span> </span><span class="code-line"><span class="token comment">// ----------------------------------------------</span> </span><span class="code-line"> </span><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;QApplication&gt;</span></span> </span><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;QObject&gt;</span></span> </span><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;QEventLoop&gt;</span></span> </span><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;QDebug&gt;</span></span> </span><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;QFileSystemWatcher&gt;</span></span> </span><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;QDirIterator&gt;</span></span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">void</span> <span class="token function">listDirectoryContents</span><span class="token punctuation">(</span> <span class="token keyword">const</span> QString<span class="token operator">&amp;</span> dir <span class="token punctuation">)</span> <span class="token keyword">noexcept</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> QFileSystemWatcher watcher<span class="token punctuation">;</span> </span><span class="code-line"> watcher<span class="token punctuation">.</span><span class="token function">addPath</span><span class="token punctuation">(</span> dir <span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> QEventLoop loop<span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token class-name">QObject</span><span class="token punctuation double-colon">::</span><span class="token function">connect</span><span class="token punctuation">(</span> <span class="token operator">&amp;</span>watcher<span class="token punctuation">,</span> <span class="token operator">&amp;</span>QFileSystemWatcher<span class="token punctuation double-colon">::</span>directoryChanged<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">(</span> <span class="token keyword">const</span> QString<span class="token operator">&amp;</span> path <span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">qDebug</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;&lt;</span> <span class="token string">&quot;\n----------------------------------------------------------&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> QDirIterator <span class="token function">it</span><span class="token punctuation">(</span> path<span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> <span class="token string">&quot;*.torrent&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// Filter: *.torrent</span> </span><span class="code-line"> QDir<span class="token punctuation double-colon">::</span>Files <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Files only</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">while</span> <span class="token punctuation">(</span> it<span class="token punctuation">.</span><span class="token function">hasNext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token comment">// List all txt files</span> </span><span class="code-line"> <span class="token punctuation">{</span> <span class="token comment">// on console</span> </span><span class="code-line"> <span class="token function">qDebug</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;&lt;</span> it<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// QObject::connect( &amp;watcher, &amp;QFileSystemWatcher::directoryChanged, &amp;loop, &amp;QEventLoop::quit );</span> </span><span class="code-line"> </span><span class="code-line"> loop<span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// Example</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token keyword">int</span> argc<span class="token punctuation">,</span> <span class="token keyword">char</span><span class="token operator">*</span><span class="token operator">*</span> argv<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">if</span> <span class="token punctuation">(</span>argc <span class="token operator">!=</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">qDebug</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;&lt;</span> <span class="token string">&quot;usage: &quot;</span> <span class="token operator">&lt;&lt;</span> <span class="token operator">*</span>argv <span class="token operator">&lt;&lt;</span> <span class="token string">&quot;path&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> QCoreApplication <span class="token function">app</span><span class="token punctuation">(</span>argc<span class="token punctuation">,</span> argv<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">const</span> QString dir <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">(</span>argv<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">listDirectoryContents</span><span class="token punctuation">(</span> dir <span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> app<span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>构建:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">qmake-qt5 </span><span class="code-line"><span class="token function">make</span> </span></code></pre></div><p>测试运行:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">./watcher /run/media/ttys3/sdc-media/game/for-watch </span></code></pre></div><p>这里的<code>/run/media/ttys3/sdc-media/game/for-watch</code>是 NTFS 移动磁盘中的一个目录。 测试的结果表明, <code>QFileSystemWatcher</code> 完全能够监视 NTFS 文件系统中的文件。</p><p>于是我重新看了下挂载参数:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">❯ <span class="token function">mount</span> <span class="token operator">|</span> <span class="token function">grep</span> /run/media/ttys3/sdc-media </span><span class="code-line">/dev/sdd5 on /run/media/ttys3/sdc-media <span class="token class-name builtin">type</span> fuseblk <span class="token punctuation">(</span>rw,nosuid,nodev,relatime,user_id<span class="token operator">=</span><span class="token number">0</span>,group_id<span class="token operator">=</span><span class="token number">0</span>,default_permissions,allow_other,blksize<span class="token operator">=</span><span class="token number">4096</span>,uhelper<span class="token operator">=</span>udisks2<span class="token punctuation">)</span> </span></code></pre></div><p>没错, 这个NTFS分区,是以 fuseblk 文件系统的方式挂载上的。具体的实现是由 <a href="https://www.tuxera.com/community/open-source-ntfs-3g/">ntfs-3g</a>实现的。</p><p>下载源码看了下,唯一跟这个相关的调用是<code>src/lowntfs-3g.c</code>中的<code>fuse_lowlevel_notify_inval_inode</code> 调用。</p><p>所以,应该是 ntfs-3g 实现的 fuseblk 已经支持 notify 了, 而内核的 inotify 也有相应的支持。</p><p>因此, <code>QFileSystemWatcher</code> 完全不用针对 NTFS 做出任何特别的判断,它只需要照单接收即可。</p><h2 id="结论"><a href="#结论" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>结论</h2><p>Linux 下以 fuseblk 或 fuse 方式挂载的 NTFS 文件系统 是支持 inotify 的, 因此 qB 能监视 这种方式挂载的 NTFS 目录。 而对于网络文件系统(比如 nfs 和 smb 之类的),qB 需要用定时器每隔一段时间对需要监视的目录进行扫描。</p><h2 id="参考"><a href="#参考" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考</h2><p><a href="https://www.tuxera.com/community/open-source-ntfs-3g/">https://www.tuxera.com/community/open-source-ntfs-3g/</a></p><p><a href="https://github.com/libfuse/libfuse/wiki/Fsnotify-and-FUSE">https://github.com/libfuse/libfuse/wiki/Fsnotify-and-FUSE</a></p><p><a href="https://blog.rburchell.com/2012/01/qfilesystemwatcher-internals-in-qt-5.html">https://blog.rburchell.com/2012/01/qfilesystemwatcher-internals-in-qt-5.html</a></p><p><a href="https://www.kernel.org/doc/html/latest/filesystems/fuse.html">https://www.kernel.org/doc/html/latest/filesystems/fuse.html</a></p><p><a href="https://www.kernel.org/doc/Documentation/filesystems/fuse.txt">https://www.kernel.org/doc/Documentation/filesystems/fuse.txt</a></p><p><a href="https://www.kernel.org/doc/html/latest/filesystems/inotify.html">https://www.kernel.org/doc/html/latest/filesystems/inotify.html</a></p><p><a href="https://www.kernel.org/doc/html/latest/filesystems/ntfs.html">https://www.kernel.org/doc/html/latest/filesystems/ntfs.html</a></p><p><a href="https://libfuse.github.io/doxygen/notify__inval__inode_8c.html">https://libfuse.github.io/doxygen/notify__inval__inode_8c.html</a></p> Mon, 08 Jun 2020 06:16:01 GMT ttyS3 qBittorrentBTFUSEBLKFUSENTFSLinuxinotifyqt5QFileSystemWatcher https://ttys3.dev/blog/please-stop-using-valine-js-comment-system-until-it-fixed-the-privacy-leaking-problem 请马上停止使用Valine.js评论系统,除非它修复了用户隐私泄露问题 https://ttys3.dev/blog/please-stop-using-valine-js-comment-system-until-it-fixed-the-privacy-leaking-problem <h2 id="缘由"><a aria-hidden="true" href="#缘由" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h2><p>Valine.js隐私泄露问题, 老灯完全是无意中发现的。老灯最近在研究一些serverless的东西,然后发现Valine.js挺多人用的。 于是也申请了一个LeanCloud国际版的id, 获取了密钥,然后开始在本地测试Valine.js</p><p>Valine.js评论系统,只需要嵌入几行js就完成了整个配置,并且API请求是直接走的LeanCloud服务器,不是像staticman那样需要有API中转。 可以说,整个体验过程非常顺畅。就功能性方面来说,Valine.js几乎是满分。</p><p>毕竟老灯之前也没怎么用serverless的东西,因此,主要目的,是学习一下serverless的这个思路,我觉得挺好的。 于是老灯习惯性地打开了Firefox控制台,看看这个serverless评论系统都发了哪些请求,这一看确实发现了一些问题。 这也是为什么有了这篇文章。</p><h2 id="valine-是如何泄露博主本人及所有评论者的隐私信息的"><a aria-hidden="true" href="#valine-是如何泄露博主本人及所有评论者的隐私信息的" tabindex="-1"><span class="icon icon-link"></span></a>Valine 是如何泄露博主本人及所有评论者的隐私信息的?</h2><p>我们先看一下官方的介绍:</p><blockquote><p>Valine - 一款快速、简洁且高效的无后端评论系统。</p><p>由于某些原因,src目录将从v1.4.0后暂停更新.</p><p>Valine 诞生于2017年8月7日,是一款基于LeanCloud的快速、简洁且高效的无后端评论系统。</p><p>理论上支持但不限于静态博客,目前已有Hexo、Jekyll、Typecho、Hugo、Ghost 等博客程序在使用Valine。</p><p>特性: 快速, 安全, Emoji 😉, 无后端实现, MarkDown 全语法支持, 轻量易用, 文章阅读量统计</p></blockquote><p>根据上面的信息,我们可得知:</p><ol><li>无后端设计,部署非常简单</li><li>这个评论系统自从 1.4.0 版 之后, 基本上就等于是不开源了,如果我的理解没有问题。</li><li>主流的静态博客基本上它都支持</li><li>功能挺全的</li></ol><p>我们先来看一下传统的CMS(或者说博客系统)的评论系统是如何设计的。以最流行的WordPress为例。</p><p>WordPress 采用 PHP + MySQL 的方案,因此它的评论是存储在server端的数据库里,里面会记录评论者的昵称,邮箱和IP及浏览器user agent信息。 但是一般的主题设计都会注重保护评论者的隐私,基本上不会直接显示邮箱和IP及浏览器user agent的完整信息。 当然,博主本人对于服务器数据库里的这些信息拥有绝对的控制权,但是就整个系统默认的设计来说,不会存在默认地隐性地隐私泄露问题。</p><p>然后我们再来看一下无后端的方案,Valine主要是使用LeanCloud的API来存取数据(评论信息)。而请求LeanCloud的API只需要两个东西: <code>AppID</code>和<code>AppKey</code>, 这两个东西, 对于 serverless 的评论系统来说,等于是对所有人是透明的。Ctrl + U 查看源码即可获取到。</p><div><img alt="" src="https://ttys3.dev/static/assets/leancloud-api-key-2020-06-08-02-20-46-QTJHDU2H.png" width="2287" height="900"/></div><div><img alt="" src="https://ttys3.dev/static/assets/valine-js-data-2020-06-08-03-19-04-ARSA77LD.png" width="2894" height="914"/></div><div><img alt="" src="https://ttys3.dev/static/assets/valine-js-data-permissions-2020-06-08-03-20-28-OV7BONYY.png" width="1427" height="1539"/></div><p>LeanCloud也有说明,<code>AppKey</code> 是公开的访问密钥,适用于在公开的客户端中使用。也就是说,任何人都可以拿到这个东西进行API请求。 由于评论者基本上分部在不同的地区,因此,这个API请求不可能限制来源IP。最多能做的也就是限制一下频率。还有限制一下请求的referer. 而<code>HTTP referer</code>这个东西在请求的时候需要伪造也是非常简单的事,可以说基本上不算限制。</p><p><code>AppKey</code> 是公开的,基本上就表示,你通过这个API创建的数据,也是公开的。</p><p>像Valine这样,在公开的数据库里存储了用户的昵称,Email, IP地址 还有 浏览器User Agent完整信息,涉及隐私的信息,虽然默认在界面没有显示, 但是一打开控制台就一览无余了,如下图,是一个实际的例子(基于隐私考虑,以下截图关键信息已打码处理):</p><div><img alt="" src="https://ttys3.dev/static/assets/valine-js-comment-system-is-leaking-your-privacy-2020-06-08-01-59-59-23VIB52I.png" width="3728" height="1486"/></div><div><img alt="" src="https://ttys3.dev/static/assets/ip-location-query-2020-06-08-02-27-53-OALRGI6X.png" width="1307" height="608"/></div><p>另外,由于 Valine 并不能确定哪个是博主,哪个是发送评论的游客,因此:</p><blockquote><p>Valine将会泄露博主本人以及所有评论者的隐私信息的</p></blockquote><p>由于纯js并不能获取用户的公网IP地址,因此 Valine 实际上是调用了一个公共的IP获取接口:<code>https://api.ip.sb/jsonip?callback=getIP</code> 调用方式为<code>jsonp</code>, 因此不会有跨域限制。</p><p>当然有人可能会反驳了,谁闲着没事来看浏览器控制台啊? 谁让你看控制台了?</p><p>有没有人来抓取这些泄露的隐私信息我不知道。 世界那么大,谁知道呢?</p><p>还有人会说,我们的隐私已经被各大平台卖得差不多了,还差这一点?</p><p>对此,老灯只想怼一句: 如果你被QJ了一次,你会觉得再被多少人QJ一次也无所谓了?</p><p>还有人会说,我的IP每天都变动,我的邮箱也算不上什么,泄露就泄露吧。</p><p>对此,老灯只想说: FK U! 你不注重,不代表别人不注重。评论系统是针对所有人的。所有评论的人都可能会使用这个系统。 不管是有意,还是无意。</p><p>既然像Valine这种默认情况下获取了用户隐私信息的serverless的评论系统无法保护用户的隐私, 老灯认为,Email, IP地址 还有 浏览器User Agent这些信息,那它就不应该在用户评论的时候自动抓取。 或者,至少在用户评论的时候,应该提醒用户,是否同意抓取这些信息。反正老灯目前没有看到这种提示。</p><p>我们来学习一下优秀的,比较注重用户隐私的评论系统的案例吧, remark42 是一个基于golang的评论系统(当然,它并不是serverless的),它使用boltdb存储用户的评论信息。 默认情况下,remark42甚至不会保存用户的邮箱地址。如果用户需要订阅评论回复怎么办?remark42有提供一个显式地“订阅邮件回复”的按钮。 尽管从remark42的实现来说,它是有后端服务的,并且一般情况下,数据库只有拥有服务器权限的人,也就是博主本人才能拿到。 所以,remark42完全有理由保存邮箱地址,但是它却没有这样做,而这样实现的主要目的,是因为remark42是比较注重隐私保护的。</p><h2 id="我正在使用-valine-我要如何做才能防止它泄露隐私"><a aria-hidden="true" href="#我正在使用-valine-我要如何做才能防止它泄露隐私" tabindex="-1"><span class="icon icon-link"></span></a>我正在使用 Valine, 我要如何做才能防止它泄露隐私?</h2><h3 id="针对博主"><a aria-hidden="true" href="#针对博主" tabindex="-1"><span class="icon icon-link"></span></a>针对博主</h3><ol><li>马上删除你博客中的Valine嵌入代码,并更新静态博客的内容</li><li>马上停止你的LeanCloud中用于Valine的app的数据存储服务 (由于LeanCloud的<code>AppID</code>和<code>AppKey</code>无法重置,因此只能停止这个key的服务),或者在导出数据后删除app</li><li>向 Valine 开发者反馈隐私泄露问题</li><li>直到 Valine 解决隐私泄露问题, 否则,老灯不建议你使用它</li></ol><h3 id="针对所有人"><a aria-hidden="true" href="#针对所有人" tabindex="-1"><span class="icon icon-link"></span></a>针对所有人</h3><p>直到 Valine 修复隐私问题,否则,当你看到任意博客的评论系统下面有“Powered By Valine”字样时,请不要提交评论。</p> Sun, 07 Jun 2020 17:58:25 GMT ttyS3 comment systemserverlessprivacy leaking https://ttys3.dev/blog/python-how-to-generate-stubs-for-binary-module Python如何给二进制模块生成stubs https://ttys3.dev/blog/python-how-to-generate-stubs-for-binary-module <p>English title: Python How to Generate Stubs for Binary Module</p><h2 id="stubs是什么"><a href="#stubs是什么" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>stubs是什么</h2><p>stubs主要是给IDE自动提示和语法检测使用的,比如<a href="https://www.jetbrains.com/pycharm/">JetBrains PyCharm</a>.</p><p>stubs有个规范的名称,叫<code>PEP 561 Typing Stubs</code></p><p><a href="https://www.python.org/dev/peps/pep-0561/#type-checker-module-resolution-order">https://www.python.org/dev/peps/pep-0561/#type-checker-module-resolution-order</a></p><blockquote><ol start="3"><li>Stub packages - these packages SHOULD supersede any installed inline package. They can be found at <code>foopkg-stubs</code> for package <code>foopkg</code>.</li></ol></blockquote><p>所以 <code>gi</code> 包(PyGTK包的顶层目录名是<code>gi</code>)的 stubs包是 <code>gi-stubs</code>.</p><p>但是使用 JetBrains <code>generator3</code> 生成的包,并不是一个真正的stub文件(<code>.pyi</code>后缀的才是stub文件), 它生成的所有的代码都是<code>.py</code>后缀的。但是,PyCharm 能正确地将它当做stubs识别。</p><p>我们使用<code>gi-stubs</code>,而不是直接使用<code>gi</code>, 一是防止user级别的包屏蔽了系统的 gi (位于<code>/usr/lib64/python3.8/site-packages/gi/</code>), 而这个包实际是个stubs,不能真正工作, 这样就会导致正常的代码无法运行,因此顶层目录名一定是<code>gi-stubs</code>而不是<code>gi</code>. 二是,根据Stub packages的规范( <code>foopkg-stubs</code> for package <code>foopkg</code>)</p><h2 id="pygobject-stubs-的不足"><a href="#pygobject-stubs-的不足" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>PyGObject-stubs 的不足</h2><p>最近尝试用py3写一点<a href="https://github.com/ttys3/gnome-nautilus-scripts">nautilus scripts</a>, 因此肯定是要用到 <a href="https://pypi.org/project/PyGTK/">PyGTK</a>模块。但是这个模块是GTK lib的一个python绑定,因此实际的代码并不在python这边。 这给IDE的语法检测和自动提示都带来了麻烦。PyCharm 完全不知道<code>from gi.repository import Gtk</code>导入的<code>Gtk</code>模块是个什么东西。但是它很智能,会机智地提示你缺少相应的stubs:</p><blockquote><p>Type hints are not installed They could make code insight better. Install &#x27;PyGObject-stubs==0.0.2&#x27;</p></blockquote><p>尝试执行一下<code>pip install --user PyGObject-stubs</code> 安装好这个stubs, 发现 PyCharm 已经可以识别<code>Gtk</code>模块了。</p><p>然后这个stubs, 如果你去看<a href="https://github.com/pygobject/pygobject-stubs/blob/d0d30668c9aa59ab46d20b4be4704f8bbdc8985c/gi-stubs/repository/Gtk.pyi">它的源码</a>,就会发现,它能做的仅仅是导入一些基本的类型定义,没有任何参数提示。</p><p>这其实没有太多作用,它能做的仅仅是能不让编辑器误认为你有语法错误。</p><h2 id="尝试自已动手生成"><a href="#尝试自已动手生成" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>尝试自已动手生成</h2><blockquote><p>如果不想自己手动生成的,可以直接使用老灯生成好的 <a href="https://github.com/ttys3/pygobject-stubs">https://github.com/ttys3/pygobject-stubs</a></p><p>使用方法: <code>git clone https://github.com/ttys3/pygobject-stubs.git /tmp/ &amp;&amp; mv /tmp/pygobject-stubs/gi-stubs ~/.local/lib/python3.8/site-packages/</code></p><p>这里的<code>python3.8</code>根据自己的实际情况修改</p></blockquote><p>Google了一下,好像早期的PyCharm有<code>Generate Stubs for Binary Module</code>这种自动生成stubs的功能,不知道为什么现在没有了。</p><p>然后在<code>PyGObject-stubs</code>的github repo发现一个有用的issue( <a href="https://github.com/pygobject/pygobject-stubs/issues/5">https://github.com/pygobject/pygobject-stubs/issues/5</a> , 里面提到了使用<code>intellij-community</code>的<code>python/helpers/generator3.py</code>脚本自动生成stubs.</p><p>不过这个issue是2018年的,有点老了。新版的JetBrains IDE已经将这个<code>generator3.py</code>脚本改写成了一个<code>generator3</code>模块了。</p><p>另外老灯发现,<code>JetBrains PyCharm</code>也自带了这个<code>generator3</code>模块。</p><p>所以,将前面发现的那个issue里的脚本稍做修改,就能适用于最新的IDE和库:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token function">mkdir</span> /tmp/out </span><span class="code-line"><span class="token keyword">for</span> <span class="token variable for-or-select">typelib</span> <span class="token keyword">in</span> Atk GLib GModule GObject Gdk GdkPixbuf Gio Gtk Pango<span class="token punctuation">;</span> <span class="token keyword">do</span> </span><span class="code-line"> <span class="token variable assign-left">PYTHONPATH</span><span class="token operator">=</span><span class="token constant environment">$HOME</span>/Apps/pycharm-community/plugins/python-ce/helpers python3 <span class="token variable parameter">-m</span> generator3 <span class="token variable parameter">-d</span> /tmp/out <span class="token variable parameter">-p</span> gi.repository.<span class="token variable">$typelib</span> <span class="token variable"><span class="token variable">$(</span>python3 <span class="token variable parameter">-c</span> <span class="token string">&quot;import gi; gi.require_versions({&#x27;Atk&#x27;: &#x27;1.0&#x27;, &#x27;GModule&#x27;: &#x27;2.0&#x27;, &#x27;Gdk&#x27;: &#x27;3.0&#x27;, &#x27;GdkPixbuf&#x27;: &#x27;2.0&#x27;, &#x27;Gtk&#x27;: &#x27;3.0&#x27;, &#x27;Pango&#x27;: &#x27;1.0&#x27;}); from gi.repository import <span class="token variable">$typelib</span>; print(<span class="token variable">$typelib</span>.__path__[-1])&quot;</span><span class="token variable">)</span></span> </span><span class="code-line"><span class="token keyword">done</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 让stubs能为PyCharm所用:</span> </span><span class="code-line"><span class="token function">mv</span> /tmp/out/gi ~/.local/lib/python3.8/site-packages/gi-stubs </span><span class="code-line"><span class="token comment"># 或者你可以将 gi-stubs 目录放到任意地址,但是要记得添加到你的项目</span> </span><span class="code-line"><span class="token comment"># 具体可以参考 https://www.jetbrains.com/help/pycharm/stubs.html#reuse-stubs</span> </span><span class="code-line"><span class="token comment"># 注意是添加父目录,比如你将 gi-stubs 放到了 `~/repo/python/stubs/gi-stubs`, 那么</span> </span><span class="code-line"><span class="token comment"># 在PyCharm里添加的时候是添加`~/repo/python/stubs`这个目录</span> </span></code></pre></div><p><code>$HOME/Apps/pycharm-community</code> 是本机 PyCharm 安装路径, 请修改为你自己的。</p><h2 id="生成命令解释"><a href="#生成命令解释" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>生成命令解释</h2><p>我们从上面的<code>for</code>里单独拿一条命令出来,以给 <code>Gtk</code> 模块生成的为例。</p><p><code>python3 -c &quot;import gi; gi.require_versions({&#x27;Gtk&#x27;: &#x27;3.0&#x27;}); from gi.repository import Gtk; print(Gtk.__path__[-1])&quot;</code> 用于找到本机Gtk模块的<code>typelib</code>文件路径:</p><p><code>/usr/lib64/girepository-1.0/Gtk-3.0.typelib</code></p><p>因此我们的生成命令其实是像这样:</p><p><code>PYTHONPATH=$HOME/Apps/pycharm-community/plugins/python-ce/helpers python3 -m generator3 -d /tmp/out -p gi.repository.Gtk /usr/lib64/girepository-1.0/Gtk-3.0.typelib</code></p><p>这个命令会使用 JetBrains <code>generator3</code> 通过解析<code>/usr/lib64/girepository-1.0/Gtk-3.0.typelib</code>这个 G-IR 格式的二进制数据库文件,生成<code>gi.repository.Gtk</code>模块的stubs.</p><h2 id="使用效果"><a href="#使用效果" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>使用效果</h2><p>自动生成的有些地方会有问题(但是基本上不影响代码自动完成),比如<code>Gdk.SELECTION_CLIPBOARD</code>没有成功解析出它的值(给弄成了<code>None</code>)</p><div class="relative"><pre><code class="code-highlight language-python"><span class="code-line">SELECTION_CLIPBOARD <span class="token operator">=</span> <span class="token boolean">None</span> <span class="token comment"># (!) real value is &#x27;Gdk.Atom.intern(&quot;CLIPBOARD&quot;, False)&#x27;</span> </span></code></pre></div><p>总体来说效果还是比<code>PyGObject-stubs</code> 好太多:</p><div><img alt="demo1" src="https://ttys3.dev/static/assets/Peek-2020-06-06-00-33-SMFR342O.gif" width="1063" height="636"/></div><div><img alt="demo2" src="https://ttys3.dev/static/assets/Peek-2020-06-06-00-34-IFVSPD76.gif" width="1063" height="636"/></div> Fri, 05 Jun 2020 16:41:10 GMT ttyS3 PythonPython StubBinary Module https://ttys3.dev/blog/install-fedora-31-on-mbp-late-2013 MBP Late 2013安装Fedora 31 https://ttys3.dev/blog/install-fedora-31-on-mbp-late-2013 <p>文章未完,待继续更新</p><p>en title: Install Fedora 31 on MacBook Pro Late 2013</p><blockquote><p>本文写于2020年春节假期,当时由于在家想玩podman容器,而mac下并没有原生的docker或podman,因此给mbp加装第二系统: Fedora 所以本文是Mac + Fedora 双系统。 由于当时Fedora 32尚未正式发布,因此文章的图片素材显示的是Fedora 31, 但是实际上Fedora 32的安装过程是一样的。 现在Fedora 32已经发布了,因此,可请自行把文章中的 31 替换成 32便可直接安装<code>Fedora 32</code>. 如果你完全按文章操作安装的F31, 如果要从F31升级到F32的,可参考<a href="https://ttys3.net/post/linux/fedora/fedora31-upgrade-to-fedora32/">Fedora 31 升级到 Fedora 32</a>一文升级</p></blockquote><blockquote><p>由于我用于安装Fedora的分区是使用了我原本是安装了ArchLinux的那个分区(也就是说,之前是Mac+ArchLinux双系统),因此这里并不涉及划分磁盘给Linux这一部分的操作。 实际操作中,如果你是单一的Mac,你需要划分一个分区出来给Linux使用, 如果需要这部分的帮助,请Goolge一下其他人的教程。 至于为什么从ArchLinux换成Fedora, 这个其实可以看之前的文章,我的台式机已经把用了10多年的ArchLinux也换成了Fedora. 主要原因是RHEL系对自家的podman肯定是支持更完善,省事。另外就是不想再用滚动升级的系统了。</p></blockquote><h2 id="准备工作"><a href="#准备工作" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>准备工作</h2><p>下载iso, 这里我选择从ustc镜像下载,速度非常快</p><p>Fedora 31下载地址:</p><p><a href="https://mirrors.ustc.edu.cn/fedora/releases/31/Workstation/x86_64/iso/">https://mirrors.ustc.edu.cn/fedora/releases/31/Workstation/x86_64/iso/</a></p><p>Fedora 32下载地址:</p><p><a href="https://mirrors.ustc.edu.cn/fedora/releases/32/Workstation/x86_64/iso/">https://mirrors.ustc.edu.cn/fedora/releases/32/Workstation/x86_64/iso/</a></p><p>下载完iso我们进行一下完整性校验,如果没有安装gpg的用brew安装一下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">brew <span class="token function">install</span> gpg </span></code></pre></div><p>参照 <a href="https://getfedora.org/en/security/">https://getfedora.org/en/security/</a> 进行校验:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">curl</span> https://getfedora.org/static/fedora.gpg <span class="token operator">|</span> gpg <span class="token variable parameter">--import</span> </span><span class="code-line"><span class="token comment">#开始校验CHECKSUM文件签名,如果看到 good signature 就OK</span> </span><span class="code-line">❯ <span class="token variable assign-left"><span class="token constant environment">LC_ALL</span></span><span class="token operator">=</span>en_US gpg --verify-files *-CHECKSUM </span><span class="code-line">gpg: Signature made Fri Oct <span class="token number">25</span> <span class="token number">21</span>:09:48 <span class="token number">2019</span> CST </span><span class="code-line">gpg: using RSA key 50CB390B3C3359C4 </span><span class="code-line">gpg: Good signature from <span class="token string">&quot;Fedora (31) &lt;[email protected]&gt;&quot;</span> <span class="token punctuation">[</span>unknown<span class="token punctuation">]</span> </span><span class="code-line">gpg: WARNING: This key is not certified with a trusted signature<span class="token operator">!</span> </span><span class="code-line">gpg: There is no indication that the signature belongs to the owner. </span><span class="code-line">Primary key fingerprint: 7D22 D586 7F2A <span class="token number">4236</span> 474B F7B8 50CB 390B 3C33 59C4 </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#最后校验sha256 hash</span> </span><span class="code-line">❯ sha256sum <span class="token variable parameter">-c</span> *-CHECKSUM </span><span class="code-line">Fedora-Workstation-Live-x86_64-31-1.9.iso: OK </span><span class="code-line">sha256sum: WARNING: <span class="token number">19</span> lines are improperly formatted </span></code></pre></div><p>参考 <a href="https://docs.centos.org/en-US/centos/install-guide/Making_Media_USB_Mac/">https://docs.centos.org/en-US/centos/install-guide/Making_Media_USB_Mac/</a> 制作 fedora 安装U盘</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ diskutil list </span><span class="code-line">/dev/disk0 <span class="token punctuation">(</span>internal, physical<span class="token punctuation">)</span>: </span><span class="code-line"><span class="token comment">#: TYPE NAME SIZE IDENTIFIER</span> </span><span class="code-line"><span class="token number">0</span>: GUID_partition_scheme *500.3 GB disk0 </span><span class="code-line"><span class="token number">1</span>: EFI EFI <span class="token number">209.7</span> MB disk0s1 </span><span class="code-line"><span class="token number">2</span>: Apple_APFS Container disk1 <span class="token number">300.9</span> GB disk0s2 </span><span class="code-line"><span class="token number">3</span>: Apple_HFS untitled <span class="token number">104.9</span> MB disk0s3 </span><span class="code-line"><span class="token number">4</span>: Linux Filesystem <span class="token number">209.7</span> MB disk0s4 </span><span class="code-line"><span class="token number">5</span>: Linux Filesystem <span class="token number">85.9</span> GB disk0s5 </span><span class="code-line"><span class="token number">6</span>: Linux Filesystem <span class="token number">107.4</span> GB disk0s6 </span><span class="code-line"> </span><span class="code-line">/dev/disk1 <span class="token punctuation">(</span>synthesized<span class="token punctuation">)</span>: </span><span class="code-line"><span class="token comment">#: TYPE NAME SIZE IDENTIFIER</span> </span><span class="code-line"><span class="token number">0</span>: APFS Container Scheme - +300.9 GB disk1 </span><span class="code-line">Physical Store disk0s2 </span><span class="code-line"><span class="token number">1</span>: APFS Volume Macintosh HD - Data <span class="token number">267.5</span> GB disk1s1 </span><span class="code-line"><span class="token number">2</span>: APFS Volume Preboot <span class="token number">81.7</span> MB disk1s2 </span><span class="code-line"><span class="token number">3</span>: APFS Volume Recovery <span class="token number">528.5</span> MB disk1s3 </span><span class="code-line"><span class="token number">4</span>: APFS Volume VM <span class="token number">1.1</span> GB disk1s4 </span><span class="code-line"><span class="token number">5</span>: APFS Volume Macintosh HD <span class="token number">10.9</span> GB disk1s5 </span><span class="code-line"> </span><span class="code-line">/dev/disk2 <span class="token punctuation">(</span>external, physical<span class="token punctuation">)</span>: </span><span class="code-line"><span class="token comment">#: TYPE NAME SIZE IDENTIFIER</span> </span><span class="code-line"><span class="token number">0</span>: GUID_partition_scheme *1.0 TB disk2 </span><span class="code-line"><span class="token number">1</span>: Microsoft Basic Data phiH1 <span class="token number">1.0</span> TB disk2s1 </span><span class="code-line"> </span><span class="code-line">/dev/disk3 <span class="token punctuation">(</span>external, physical<span class="token punctuation">)</span>: </span><span class="code-line"><span class="token comment">#: TYPE NAME SIZE IDENTIFIER</span> </span><span class="code-line"><span class="token number">0</span>: *7.9 GB disk3 </span></code></pre></div><p>卸载USB磁盘</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ diskutil unmountDisk /dev/disk3 </span><span class="code-line">Unmount of all volumes on disk3 was successful </span></code></pre></div><p>写盘</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> <span class="token function">dd</span> <span class="token variable assign-left">if</span><span class="token operator">=</span>/Users/hacklog/Downloads/Fedora-Workstation-Live-x86_64-31-1.9.iso <span class="token variable assign-left">of</span><span class="token operator">=</span>/dev/rdisk3 <span class="token variable assign-left">bs</span><span class="token operator">=</span>8m </span><span class="code-line">Password: </span><span class="code-line"><span class="token number">460</span>+0 records <span class="token keyword">in</span> </span><span class="code-line"><span class="token number">460</span>+0 records out </span><span class="code-line"><span class="token number">1929379840</span> bytes transferred <span class="token keyword">in</span> <span class="token number">230.188987</span> secs <span class="token punctuation">(</span><span class="token number">8381721</span> bytes/sec<span class="token punctuation">)</span> </span></code></pre></div><p>写完盘, Mac 会提示不能识别, 点击Eject 就行。 如果点了ignore, 需要手动 diskutil unmountDisk /dev/disk3 再卸载一下</p><h2 id="安装fedora"><a href="#安装fedora" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装Fedora</h2><p>首先我们先在Mac下面确认一下我们需要将哪些分区给Fedora使用, 从下图可看到我之前的ArchLinux用了3个分区, <code>disk0s4</code> - <code>disk0s6</code>, 先用手机将这个分区表情况拍照记录,以便接下来在Fedora系统安装过程中分区的时候,不会错误地损坏 Mac OSX 的分区。</p><div><img alt="" src="https://ttys3.dev/static/assets/mac-show-disk-part-2020-06-05-00-33-42-BSALSGNA.png" width="750" height="960"/></div><p>参考 <a href="https://support.apple.com/en-us/HT202796">https://support.apple.com/en-us/HT202796</a> 从U盘启动Mac book pro:</p><blockquote><p>在按下开机键或系统重启后,马上按住Option (Alt),直到出现启动管理器界面才松开,然后就可以选择从我们制作好的Fedora U盘启动 If you press and hold the Control key during this step, your selection is saved in Startup Disk preferences, so it persists until you change it.</p></blockquote><p>注意下图,这里有点令人困惑,因为我之前的ArchLinux也是基于UEFI启动的,所以加上我们刚才制作的 Fedora 安装U盘,会出现两个EFI Boot的选项, 所幸的是,我们能从移动设备的黄色图标看出,最右边那个才是我们的Fedora 安装U盘。</p><div><img alt="" src="https://ttys3.dev/static/assets/mac-startup-manager-win-2020-06-05-00-55-19-D3OE2WNL.png" width="892" height="618"/></div><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-media-boot-2020-06-05-00-58-19-LGODL72S.png" width="1828" height="322"/></div><p>选择Install to Hard Drive并没有什么特别,它只是直接给你启动了一个安装器而已:</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-live-media-2020-06-05-01-00-28-VC2ICTJC.png" width="1514" height="1090"/></div><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-timezone-selection-2020-06-05-01-02-25-DVQULD25.png" width="1812" height="1136"/></div><p>可以看到,ntp客户端默认是不能工作的(因为没连网):</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-ntp-err-due-to-network-problem-2020-06-05-01-03-17-ZLLC24FQ.png" width="1646" height="640"/></div><p>接下来我们要选择安装系统到哪个分区了。</p><p>Fedora这个安装器的好处是,虽然它默认是满屏幕显示,但是其实它是运行在Live系统的一个GUI程序而已。 因此我们在安装过程中,完全可以启动任意Live系统里默认内置的程序。</p><p>在操作磁盘分区之前,我们先再次确认一下磁盘分区.</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-show-disk-part-2020-06-05-01-07-10-6LWLOUC7.png" width="852" height="584"/></div><p>然后我们对比一下之前拍照记录下的那个图,发现分区顺序和大小都是对应的。 (注意在Mac磁盘管理工具下展示的disk0s4 - disk0s6与Linux的 sda5 - sda6 的大小并不完全相同。)</p><p>在设备选择处,我们这里只有一个内置的SSD,当然就选这个了。 然后,存储配置方式那里,我们选 <code>Custom</code> (自定义)。对于这种已经有数据的盘(双系统),我们必须选<code>Custom</code> 或者 <code>Advanced Custom(Blivet-GUI)</code></p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-disk-choose-2020-06-05-01-11-50-UCJPMJ7J.png" width="958" height="706"/></div><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-disk-old-part-clear-2020-06-05-01-15-46-42DAHYHJ.png" width="534" height="668"/></div><p>这三个分区的数据我已经备份了,并且不需要了。因此,这一步主要是删除这3个分区。选中之后,点下面的<code>-</code>按钮删除即可。</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-old-linux-part-removed-2020-06-05-01-21-27-HIRLIGBW.png" width="940" height="1208"/></div><p>可以看到,删除旧分区后,我们大概剩下 185GB 的空余的磁盘空间可用了。这些空余空间等会就给Fedora用。</p><p>删除前后的分区情况确认:</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-fdisk-list-part-2020-06-05-01-20-18-LLROYOD4.png" width="1308" height="978"/></div><p>让Fedora自动分区,然后我们对于大小稍做调整,最终效果如下:</p><p>老灯根据以往自己的使用情况, 对这 185GB 空闲进行了一个合理的分配。</p><p><code>/boot</code>分了1GB,方便以后往里面塞一些小的iso维护系统,由GRUB直接启动。</p><p>由于笔记本有16GB内存,因此对于swap的需求并不是很大,分配8GB左右即可。</p><p>而<code>/</code>呢?由于要使用容器, <code>/var</code>一般会占用至少几十GB的空间。因此也不能分配太小了。 但是我这里由于容量有限,因此也没有必要把<code>/var</code>单独分出来持载了。</p><p>好了,剩下的尽量多的空间,都给<code>/home</code>来存文件了。</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-partitions-2020-06-05-01-24-14-VYWXWOJ6.png" width="962" height="1138"/></div><p>这是Fedora 31默认的分区策略。总共4个物理分区:<code>/boot/efi</code>(sda4, EFI) <code>/boot/efi</code>(sda5, HFS+ ESP), <code>/boot</code>(sda6) 和 LVM(sda7). 然后在LVM上面再分出<code>/home</code>, <code>/</code> 和 <code>swap</code> 分区。</p><p>别的分区都没啥说的,这里有一个细节值得注意,那就是<code>/boot/efi</code>分区的文件系统格式:</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-on-mbp-efi-partition-2020-06-05-01-28-55-5P3CYO7A.png" width="1644" height="1172"/></div><p>对于Windows 10 + Linux双系统,一般我们的efi分区都是弄成vfat的。</p><p>但是这里,Fedora默认给我们设置好的分区格式是 <code>HFS+ ESP</code>。</p><p>为什么?</p><blockquote><p>The EFI system partition (also called ESP)</p><p>The default mac bootloader can only boot from HFS+ partitions. SO fedora creates that boot partition for you to use instead of a a normal fat32 partition so that you can keep the native mac bootloader.</p></blockquote><p>因为默认情况下,Mac的启动管理器只能从<code>HFS+</code>分区启动,所以Fedora机智地给你自动设置好了这个文件系统。</p><p>最终确认:</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-partition-confirm-2020-06-05-01-37-26-IT3AZQ22.png" width="1638" height="990"/></div><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-partition-confirm-2-2020-06-05-01-39-09-FQCQ5VPD.png" width="1578" height="950"/></div><p>从这个图可看出,在图形界面,实际上还有一个<code>/boot/efi</code>(sda4, EFI)分区没有显示出来,但是会自动创建。 这个EFI分区,跟<code>HFS+ ESP</code>的大小一样是600M.</p><p>但是后面系统安装完成后会发现,那个vfat格式的<code>/boot/efi</code>(sda4, EFI)分区并没有被使用。在mbp上,Fedora只使用了 <code>/boot/efi</code>(sda5, HFS+ ESP)</p><p>分区操作完成后,我们再进Terminal确认一下这个分区是否OK:</p><div><img alt="" src="https://ttys3.dev/static/assets/fedora-install-part-result-confirm-2020-06-05-01-48-42-4Q4CPGWO.png" width="1448" height="984"/></div><p>然后就开始安装了。</p><p>安装好之后我们再进Mac的启动管理器看看:</p><div><img alt="" src="https://ttys3.dev/static/assets/mac-startup-manager-fedora-boot-option-2020-06-05-01-55-02-ZJFOMMU6.png" width="974" height="656"/></div><p>最后秀一个此次装机的御用U盘:</p><div><img alt="" src="https://ttys3.dev/static/assets/the-usb-drive-2020-06-05-02-34-46-L2PSGMYB.png" width="852" height="548"/></div><h2 id="解决网络问题"><a href="#解决网络问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>解决网络问题</h2><p>由于Mac基本上是使用BCM的无线芯片居多,我这个mbp也不例外。</p><p>通过<code>lspci</code>可知是一块<code>BCM4360</code>的无线网卡(BCM4360 802.11ac Wireless Network Adapter (rev 03))。</p><p>而BCM向来是不开源驱动的,因此像Fedora这样的偏向于“非GPL不取”的系统(因为会引发legal问题,RHEL是商业公司), 自然是没办法内置BCM的驱动。</p><p>现在的问题是,mbp本身是没有以太网 RJ45接口的。 而我翻了一下电脑包,我的USB转RJ45 接口线也忘记带回来了。 要让Fedora连网的前提是无线驱动要工作,而要安装BCM的驱动的前提是Fedora必须连上网,而mbp本身现在没法直接连网。 怎么办?好像是个死循环。</p><p>办法当然是有的。山人自有妙计。</p><p>几乎所有的Android手机都会有 <strong>USB网络共享</strong> 的功能,简单来说,可以通过USB连接手机和电脑,然后使手机作为一个USB网卡设备。</p><div><img alt="" src="https://ttys3.dev/static/assets/android-usb-network-share-for-mbp-2020-06-05-02-05-05-PNC5XRFE.png" width="826" height="860"/></div><p>OK, 成功连接网络,由于手机是直接使用了WIFI网络的,因此也不至于太慢。</p><h2 id="换成国内镜像"><a href="#换成国内镜像" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>换成国内镜像</h2><p>联网成功之后最重要的一件事当然是安装无线网卡驱动,但是在安装东西之前,我们最好设置一下系统镜像。</p><p>老灯偏向于使用ustc或清华大学的源,非常稳, 阿里的源也很快,但是有时候会抽风。</p><p><a href="https://mirror.tuna.tsinghua.edu.cn/help/fedora/">https://mirror.tuna.tsinghua.edu.cn/help/fedora/</a></p><p><a href="http://mirrors.ustc.edu.cn/help/fedora.html">http://mirrors.ustc.edu.cn/help/fedora.html</a></p><p>为了方便退回原来的文件,老灯这里使用git来保存好原来的文件。然后就可以大胆修改了。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">cd</span> /etc/yum.repos.d </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">git</span> init <span class="token builtin class-name">.</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">git</span> <span class="token function">add</span> <span class="token builtin class-name">.</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">git</span> commit <span class="token variable parameter">-m</span> <span class="token string">&#x27;init commit&#x27;</span> </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">sed</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^metalink=|#metalink=|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^#baseurl=http://download.fedoraproject.org/pub/fedora/linux|baseurl=https://mirrors.tuna.tsinghua.edu.cn/fedora|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-i.bak</span> <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-modular.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-updates.repo <span class="token punctuation">\</span> </span><span class="code-line"> /etc/yum.repos.d/fedora-updates-modular.repo </span></code></pre></div><h2 id="启用rpmfusion源"><a href="#启用rpmfusion源" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>启用rpmfusion源</h2><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-<span class="token variable"><span class="token variable">$(</span><span class="token function">rpm</span> <span class="token variable parameter">-E</span> %fedora<span class="token variable">)</span></span>.noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-<span class="token variable"><span class="token variable">$(</span><span class="token function">rpm</span> <span class="token variable parameter">-E</span> %fedora<span class="token variable">)</span></span>.noarch.rpm </span></code></pre></div><p>默认源还是慢,我们可以换成清华源的mirror <a href="https://mirror.tuna.tsinghua.edu.cn/help/rpmfusion/">https://mirror.tuna.tsinghua.edu.cn/help/rpmfusion/</a></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">cd</span> /etc/yum.repos.d </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">sed</span> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^metalink=|#metalink=|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-e</span> <span class="token string">&#x27;s|^#baseurl=http://download1.rpmfusion.org/|baseurl=https://mirrors.tuna.tsinghua.edu.cn/rpmfusion/|g&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-i.bak</span> <span class="token punctuation">\</span> </span><span class="code-line"> rpmfusion-free.repo <span class="token punctuation">\</span> </span><span class="code-line"> rpmfusion-free-updates.repo <span class="token punctuation">\</span> </span><span class="code-line"> rpmfusion-free-updates-testing.repo <span class="token punctuation">\</span> </span><span class="code-line"> rpmfusion-nonfree.repo <span class="token punctuation">\</span> </span><span class="code-line"> rpmfusion-nonfree-updates.repo <span class="token punctuation">\</span> </span><span class="code-line"> rpmfusion-nonfree-updates-testing.repo </span></code></pre></div><p>ps: ustc也提供rpmfusion源的 <a href="https://mirrors.ustc.edu.cn/help/rpmfusion.html">https://mirrors.ustc.edu.cn/help/rpmfusion.html</a></p><h2 id="无线驱动安装"><a href="#无线驱动安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>无线驱动安装</h2><p>我们先看下网卡硬件型号</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro ~<span class="token punctuation">]</span>$ lspci <span class="token operator">|</span> <span class="token function">grep</span> <span class="token variable parameter">-i</span> Network </span><span class="code-line">03:00.0 Network controller: Broadcom Inc. and subsidiaries BCM4360 <span class="token number">802</span>.11ac Wireless Network Adapter <span class="token punctuation">(</span>rev 03<span class="token punctuation">)</span> </span></code></pre></div><p>OK, 型号是 <code>BCM4360</code></p><p>Fedora下要使用BCM的无线网卡或蓝牙,我们需要安装 <code>broadcom-wl</code> 专有驱动.</p><p>注意<code>akmod-wl</code>和<code>broadcom-wl</code>包都是在<code>@rpmfusion-nonfree</code>仓库的,这就是为什么前面我们需要启用<code>rpmfusion</code>源。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> akmod-wl </span></code></pre></div><h2 id="显卡驱动安装"><a href="#显卡驱动安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>显卡驱动安装</h2><blockquote><p>注意: mbp late 2013是个双显卡的机器,内置了<code>Intel Iris Pro</code>显卡,还有独立的<code>NVIDIA GeForce 750M</code>显卡。 <code>lspci</code> 可看到<code>NVIDIA Corporation GK107M [GeForce GT 750M Mac Edition] (rev a1)</code>, 但是集成显卡<code>Intel Iris Pro</code>显卡默认对非Mac系统是隐藏的,所以在Linux下默认看不到这个硬件。需要hack方法才能开启这玩意, 还挺麻烦的,这里就先不折腾了,先用N卡吧。</p></blockquote><p>Fedora对于N卡的机器,默认安装使用的是开源的<code>nouveau</code>驱动, 我安装完后使用不到半小时这个驱动就crash了, 还是换成专有驱动吧,这个时候,开源还是闭源无所谓了,咱不讲究了,能稳定使用就OK:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro ~<span class="token punctuation">]</span>$ lspci <span class="token operator">|</span> <span class="token function">grep</span> <span class="token variable parameter">-E</span> <span class="token string">&#x27;VGA|Video&#x27;</span> </span><span class="code-line">01:00.0 VGA compatible controller: NVIDIA Corporation GK107M <span class="token punctuation">[</span>GeForce GT 750M Mac Edition<span class="token punctuation">]</span> <span class="token punctuation">(</span>rev a1<span class="token punctuation">)</span> </span></code></pre></div><p>nvidia驱动我们可以不用从官方网站下载,直接通过从<code>rpmfusion</code>源来安装</p><p>额外的操作:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf groupupdate core </span><span class="code-line"><span class="token function">sudo</span> dnf groupupdate multimedia <span class="token variable parameter">--setop</span><span class="token operator">=</span><span class="token string">&quot;install_weak_deps=False&quot;</span> <span class="token variable parameter">--exclude</span><span class="token operator">=</span>PackageKit-gstreamer-plugin </span><span class="code-line"><span class="token function">sudo</span> dnf groupupdate sound-and-video </span></code></pre></div><p>然后开始安装驱动</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> akmod-nvidia <span class="token comment"># rhel/centos users can use kmod-nvidia instead</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> xorg-x11-drv-nvidia-cuda <span class="token comment">#optional for cuda/nvdec/nvenc support</span> </span><span class="code-line"><span class="token function">sudo</span> dnf update <span class="token variable parameter">-y</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> xorg-x11-drv-nvidia-cuda-libs </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> vdpauinfo libva-vdpau-driver libva-utils </span></code></pre></div><h2 id="更新grub2配置"><a href="#更新grub2配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>更新GRUB2配置</h2><p>/etc/grub2-efi.cfg is a symlink to the real grub.cfg (i.e. /boot/efi/EFI/fedora/grub.cfg)</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">grub2-mkconfig <span class="token variable parameter">-o</span> /boot/efi/EFI/fedora/grub.cfg </span><span class="code-line"><span class="token comment">#或者</span> </span><span class="code-line">grub2-mkconfig <span class="token variable parameter">-o</span> /etc/grub2-efi.cfg </span></code></pre></div><p><a href="https://fedoraproject.org/wiki/GRUB_2?rd=Grub2#Updating_GRUB_2_configuration_on_UEFI_systems">https://fedoraproject.org/wiki/GRUB_2?rd=Grub2#Updating_GRUB_2_configuration_on_UEFI_systems</a></p><h2 id="常用软件安装"><a href="#常用软件安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>常用软件安装</h2><h3 id="安装实用命令行工具"><a href="#安装实用命令行工具" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装实用命令行工具</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> ncdu nload <span class="token function">htop</span> ripgrep xclip </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># https://github.com/imsnif/bandwhich</span> </span><span class="code-line"><span class="token function">sudo</span> dnf copr <span class="token builtin class-name">enable</span> atim/bandwhich <span class="token variable parameter">-y</span> <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> dnf <span class="token function">install</span> bandwhich </span><span class="code-line"><span class="token comment">#或者 cargo install bandwhich</span> </span><span class="code-line"><span class="token comment">#让普通用户可以不用sudo执行bandwhich</span> </span><span class="code-line"><span class="token function">sudo</span> setcap cap_sys_ptrace,cap_dac_read_search,cap_net_raw,cap_net_admin+ep <span class="token variable"><span class="token variable">`</span><span class="token function">which</span> bandwhich<span class="token variable">`</span></span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#https://github.com/timvisee/ffsend</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> openssl-devel </span><span class="code-line"><span class="token function">cargo</span> <span class="token function">install</span> ffsend <span class="token variable parameter">-f</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#https://github.com/mookid/diffr</span> </span><span class="code-line"><span class="token function">cargo</span> <span class="token function">install</span> diffr </span></code></pre></div><p>ncdu 实用alias:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">alias</span> <span class="token variable assign-left">ncduroot</span><span class="token operator">=</span><span class="token string">&#x27;ncdu --exclude /dev --exclude /media --exclude /mnt --exclude /proc --exclude /sys --exclude /run /&#x27;</span> </span></code></pre></div><h2 id="dnf-使用-proxy"><a href="#dnf-使用-proxy" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>dnf 使用 proxy</h2><p>使用了国内镜像之后,一般不太需要再使用proxy了,但是对于非官方镜像的 corp源 或一些第三方源(典型的比如vscode的),是没有国内镜像的。 编辑 <code>/etc/dnf/dnf.conf</code> 在[main]段添加上类似如下配置(如果不需要认证,可省略proxy_username 和 proxy_password)</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token attr-name key">proxy</span><span class="token punctuation">=</span><span class="token attr-value value">http://地址:端口</span> </span><span class="code-line"><span class="token attr-name key">proxy_username</span><span class="token punctuation">=</span><span class="token attr-value value">用户名</span> </span><span class="code-line"><span class="token attr-name key">proxy_password</span><span class="token punctuation">=</span><span class="token attr-value value">密码</span> </span></code></pre></div><h3 id="安装-vscode"><a href="#安装-vscode" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装 vscode</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">rpm</span> <span class="token variable parameter">--import</span> https://packages.microsoft.com/keys/microsoft.asc </span><span class="code-line"><span class="token function">sudo</span> <span class="token function">sh</span> <span class="token variable parameter">-c</span> <span class="token string">&#x27;echo -e &quot;[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc&quot; &gt; /etc/yum.repos.d/vscode.repo&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">sudo</span> dnf check-update </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> code </span></code></pre></div><h3 id="安装视频播放器"><a href="#安装视频播放器" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装视频播放器</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> smplayer smplayer-themes smtube youtube-dl </span></code></pre></div><h3 id="安装图片浏览器"><a href="#安装图片浏览器" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装图片浏览器</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> gthumb qimgv </span></code></pre></div><h3 id="安装邮件客户端"><a href="#安装邮件客户端" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装邮件客户端</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> geary </span></code></pre></div><h3 id="java-环境"><a href="#java-环境" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>java 环境</h3><p>Fedora 默认安装的是<code>java-1.8.0-openjdk-headless</code> , 这个jdk是不带图形(比如awt)和音频支持的, 一般我们作为桌面环境来使用,需要安装<code>java-1.8.0-openjdk</code>:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> java-1.8.0-openjdk </span></code></pre></div><h2 id="常用服务安装"><a href="#常用服务安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>常用服务安装</h2><h3 id="mbp-cpu-风扇控制"><a href="#mbp-cpu-风扇控制" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>mbp CPU 风扇控制</h3><p>使用一段时间,发现CPU温度经常在80度以上,风扇也不怎么转. 还好找到一个专门为mbp而生的工具: <code>mbpfan</code></p><p><a href="https://ineed.coffee/992/mbpfan-v1-4-0-is-out/">https://ineed.coffee/992/mbpfan-v1-4-0-is-out/</a> <a href="https://ineed.coffee/projects/mbpfan/">https://ineed.coffee/projects/mbpfan/</a> <a href="https://github.com/linux-on-mac/mbpfan">https://github.com/linux-on-mac/mbpfan</a></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># fancontrol 没法工作</span> </span><span class="code-line"><span class="token comment"># `lm_sensors`的sensors命令也没法为它生成配置文件</span> </span><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro ttys3<span class="token punctuation">]</span><span class="token comment"># fancontrol</span> </span><span class="code-line">Loading configuration from /etc/fancontrol <span class="token punctuation">..</span>. </span><span class="code-line">Error: Can&#x27;t <span class="token builtin class-name">read</span> configuration <span class="token function">file</span> </span><span class="code-line"> </span><span class="code-line">/usr/sbin/pwmconfig: There are no pwm-capable sensor modules installed </span></code></pre></div><p>看看没安装<code>mbpfan</code>之前空载的机器CPU温度:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro ttys3<span class="token punctuation">]</span><span class="token comment"># sensors</span> </span><span class="code-line">coretemp-isa-0000 </span><span class="code-line">Adapter: ISA adapter </span><span class="code-line">Package <span class="token function">id</span> <span class="token number">0</span>: +83.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span><span class="code-line">Core <span class="token number">0</span>: +81.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span><span class="code-line">Core <span class="token number">1</span>: +83.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span><span class="code-line">Core <span class="token number">2</span>: +80.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span><span class="code-line">Core <span class="token number">3</span>: +80.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span></code></pre></div><p>安装之后温度瞬间降下来了:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro ttys3<span class="token punctuation">]</span><span class="token comment">#dnf install -y mbpfan</span> </span><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro ttys3<span class="token punctuation">]</span><span class="token comment">#systemctl enable --now mbpfan</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro ttys3<span class="token punctuation">]</span><span class="token comment">#sensors coretemp-isa-0000</span> </span><span class="code-line">coretemp-isa-0000 </span><span class="code-line">Adapter: ISA adapter </span><span class="code-line">Package <span class="token function">id</span> <span class="token number">0</span>: +63.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span><span class="code-line">Core <span class="token number">0</span>: +61.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span><span class="code-line">Core <span class="token number">1</span>: +63.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span><span class="code-line">Core <span class="token number">2</span>: +61.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span><span class="code-line">Core <span class="token number">3</span>: +60.0°C <span class="token punctuation">(</span>high <span class="token operator">=</span> +84.0°C, crit <span class="token operator">=</span> +100.0°C<span class="token punctuation">)</span> </span></code></pre></div><p>mbpfan的默认配置在 /etc/mbpfan.conf ,默认的配置基本上不需要调整就可以工作得很好. 打开个kvm win10虚拟机,然后 用<code>watch -n2 sensors coretemp-isa-0000</code> 观察温度变量,基本上控制在60度左右。</p><h3 id="安装-cockpit-web-ui"><a href="#安装-cockpit-web-ui" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装 cockpit WEB UI</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> cockpit cockpit-bridge cockpit-dashboard cockpit-networkmanager <span class="token punctuation">\</span> </span><span class="code-line">cockpit-packagekit cockpit-storaged cockpit-system cockpit-ws<span class="token punctuation">\</span> </span><span class="code-line">cockpit-selinux cockpit-podman cockpit-machines cockpit-kdump cockpit-sosreport </span></code></pre></div><p>安装tuned (配合cockpit ui使用):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> tuned </span></code></pre></div><h3 id="kvm-虚拟机"><a href="#kvm-虚拟机" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>kvm 虚拟机</h3><p>准备工作: 因为windows默认不包含VirtIO driver,因此需要单独下载: stable <a href="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso">https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso</a> latest: <a href="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso">https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso</a></p><p>文件copy过去,会自动继承selinux label.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> <span class="token function">rsync</span> <span class="token variable parameter">-avP</span> ./virtio-win-0.1.173.iso /var/lib/libvirt/images/ </span></code></pre></div><p>创建vm: 登录cockpit WEB UI,然后在虚拟机那里新建一个windows 10虚拟机。</p><p>vm启动之后,直接关闭即可. 因为我们还要挂载设置virtio 驱动. 之所以要启动一次VM是因为如果不启动, cdrom 不会挂载上.</p><p>cockpit WEB UI功能比较简陋,因此我们要手动编辑虚拟机配置文件来挂载iso文件:</p><p>编辑vm xml配置文件,把virtio-win.iso 挂载上</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro libvirt<span class="token punctuation">]</span><span class="token comment"># virsh list --all</span> </span><span class="code-line"> Id Name State </span><span class="code-line">------------------------ </span><span class="code-line"> - win10 shut off </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro libvirt<span class="token punctuation">]</span><span class="token comment"># virsh edit win10</span> </span><span class="code-line">Domain win10 XML configuration edited. </span></code></pre></div><p>复制已有的配置:</p><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>disk</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>file<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">device</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>cdrom<span class="token punctuation">&#x27;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>driver</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>qemu<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>raw<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span> <span class="token attr-name">file</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>/var/lib/libvirt/images/W10_RS5_LTSC<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>target</span> <span class="token attr-name">dev</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>sdb<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>sata<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>readonly</span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>drive<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">controller</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">unit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>1<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>disk</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>稍修改下iso文件的路径(source <code>file=</code>)和设备名称(target <code>dev=</code>)及address <code>unit=</code>:</p><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>disk</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>file<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">device</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>cdrom<span class="token punctuation">&#x27;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>driver</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>qemu<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>raw<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span> <span class="token attr-name">file</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>/var/lib/libvirt/images/virtio-win-0.1.173.iso<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>target</span> <span class="token attr-name">dev</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>sdc<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>sata<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>readonly</span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>drive<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">controller</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">unit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>2<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>disk</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>保存好之后,我们再看disks部分已经有我们刚才添加的iso了:</p><p>然后,进入cockpit virtual machines管理界面,将.qow2 磁盘的bus从原来的sata改成<code>virtio</code>, 将网卡的model type 从原来的e1000e 改成 <code>virtio</code>. 然后点击run启动.</p><p>我们使用 remmina 来通过<code>spice</code>协议连接 127.0.0.1:5900</p><p>没有安装remmina的可以安装一下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> remmina remmina-plugins-exec remmina-plugins-nx remmina-plugins-rdp remmina-plugins-secret remmina-plugins-spice remmina-plugins-st remmina-plugins-vnc remmina-plugins-xdmcp </span></code></pre></div><p>iso文件权限设置 启用selinux的情况下, iso镜像文件需要有virt_image_t 类型才能被访问. 因此,通常情况,用户Home目录下的iso文件是无法访问的,最简单的解决办法是把iso文件复制到 /var/lib/libvirt/images/ 目录.</p><p>SELinux prevents guest images from loading if SELinux is enabled and the images are not correctly labeled. SELinux requires that image files have the <code>virt_image_t</code> label applied to them. The <code>/var/lib/libvirt/images</code> directory has this label applied to it and its contents by default. This does not mean that images must be stored in this directory; images can be stored anywhere, provided they are labeled with <code>virt_image_t</code>.</p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/virtualization/sect-virtualization-security_for_virtualization-selinux_and_virtualization">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/virtualization/sect-virtualization-security_for_virtualization-selinux_and_virtualization</a></p><p>由于我这个win安装盘的iso文件在ntfs分区(外挂的移动硬盘),因此其label为 <code>fusefs_t</code>,并且是不能修改的,所以我这里只能采用复制文件法.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro qb<span class="token punctuation">]</span>$ <span class="token function">ls</span> <span class="token variable parameter">-lhpZ</span> ./W10_RS5_LTSC.iso </span><span class="code-line">-rwxrwxrwx. <span class="token number">1</span> ttys3 ttys3 system_u:object_r:fusefs_t:s0 <span class="token number">1</span>.4G Jan <span class="token number">30</span> <span class="token number">23</span>:44 ./W10_RS5_LTSC.iso </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#将其复制到`/var/lib/libvirt/images/`目录:</span> </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro qb<span class="token punctuation">]</span>$ <span class="token function">sudo</span> <span class="token function">cp</span> MPBGamerElegantEdition.iso /var/lib/libvirt/images/ </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro qb<span class="token punctuation">]</span>$ <span class="token function">sudo</span> <span class="token function">ls</span> <span class="token variable parameter">-lhZ</span> /var/lib/libvirt/images/ </span><span class="code-line">total <span class="token number">1</span>.4G </span><span class="code-line">-rwxr-xr-x. <span class="token number">1</span> root root unconfined_u:object_r:virt_image_t:s0 <span class="token number">1</span>.4G Jan <span class="token number">31</span> <span class="token number">16</span>:32 MPBGamerElegantEdition.iso </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro qb<span class="token punctuation">]</span>$ </span></code></pre></div><p>windows安装界面进去后会看不到任何磁盘. 安装好<code>virtio scsi</code>驱动后即可看到. 点击Load driver 后选择virtio-win iso文件挂载的cdrom下的amd64目录下的w10目录即可. 也可以顺便把virtio网卡驱动也安装一下(NetKVM目录).</p><p>只有一个PCI设备是未知设备:<code>1af4:1045</code> 经查询 <a href="https://pci-ids.ucw.cz/read/PC/1af4/1045">https://pci-ids.ucw.cz/read/PC/1af4/1045</a> 是 Virtio memory balloon 进入Balloon 目录,安装好驱动之后,执行 blnsvr -i 安装服务</p><p>进入 <a href="https://www.spice-space.org/download.html#windows-binaries">https://www.spice-space.org/download.html#windows-binaries</a> 下载 Windows SPICE agent the SPICE guest agent (for copy and paste, automatic resolution switching, ...)</p><p>把下载的工具打包成一个iso,方便挂载给guest机用:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">mkisofs</span> <span class="token variable parameter">-V</span> ttys3-win10-tools <span class="token variable parameter">-f</span> <span class="token variable parameter">-J</span> -joliet-long <span class="token variable parameter">-r</span> -allow-lowercase -allow-multidot <span class="token variable parameter">-o</span> ttys3-win10-tools.iso <span class="token builtin class-name">.</span> </span></code></pre></div><div class="relative"><pre><code class="code-highlight language-xml"><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>disk</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>file<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">device</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>cdrom<span class="token punctuation">&#x27;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>driver</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>qemu<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>raw<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span> <span class="token attr-name">file</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>/var/lib/libvirt/images/ttys3-win10-tools.iso<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>target</span> <span class="token attr-name">dev</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>sdd<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>sata<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>readonly</span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>drive<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">controller</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>0<span class="token punctuation">&#x27;</span></span> <span class="token attr-name">unit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&#x27;</span>3<span class="token punctuation">&#x27;</span></span><span class="token punctuation">/&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>disk</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>qemu guest agent无法成功安装, 原因是 这个系统精简掉了这个程序依赖的VSS服务( Volume Shadow Copy Service)</p><h3 id="samba文件共享"><a href="#samba文件共享" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>samba文件共享</h3><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro /<span class="token punctuation">]</span>$ <span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> samba </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro /<span class="token punctuation">]</span>$ <span class="token function">sudo</span> systemctl <span class="token builtin class-name">enable</span> <span class="token variable parameter">--now</span> smb </span><span class="code-line">Created symlink /etc/systemd/system/multi-user.target.wants/smb.service → /usr/lib/systemd/system/smb.service. </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro /<span class="token punctuation">]</span>$ <span class="token function">sudo</span> systemctl <span class="token builtin class-name">enable</span> <span class="token variable parameter">--now</span> nmb </span><span class="code-line">Created symlink /etc/systemd/system/multi-user.target.wants/nmb.service → /usr/lib/systemd/system/nmb.service. </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 如果共享的目录就是当前登录DE的用户的话,其实不用额外加一个 winshare 用户了</span> </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro /<span class="token punctuation">]</span>$ <span class="token function">sudo</span> <span class="token function">useradd</span> <span class="token variable parameter">-c</span> <span class="token string">&#x27;smb user for win share&#x27;</span> <span class="token variable parameter">-d</span> /usr/share/empty <span class="token variable parameter">-M</span> <span class="token variable parameter">-N</span> <span class="token variable parameter">-s</span> /sbin/nologin winshare </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro /<span class="token punctuation">]</span>$ <span class="token function">sudo</span> smbpasswd <span class="token variable parameter">-a</span> winshare </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 允许kvm虚拟机连接本机的默认zone下的监听的smb (比如通过局域网IP)</span> </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro media<span class="token punctuation">]</span>$ <span class="token function">sudo</span> firewall-cmd <span class="token variable parameter">--permanent</span> --add-service<span class="token operator">=</span>samba </span><span class="code-line">success </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 允许kvm虚拟机连接本机libvirt zone网卡上监听的smb(通过virbr0网卡的IP连接)</span> </span><span class="code-line"><span class="token comment"># win: net use z: \\192.168.122.1\winshare /user:ttys3 &quot;密码&quot; /persistent:yes</span> </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro media<span class="token punctuation">]</span>$ <span class="token function">sudo</span> firewall-cmd <span class="token variable parameter">--permanent</span> --add-service<span class="token operator">=</span>samba <span class="token variable parameter">--zone</span><span class="token operator">=</span>libvirt </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span>ttys3@HuangYeMacBookPro media<span class="token punctuation">]</span>$ <span class="token function">sudo</span> firewall-cmd <span class="token variable parameter">--reload</span> </span><span class="code-line">success </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro /<span class="token punctuation">]</span><span class="token comment"># setsebool -P samba_export_all_rw=1</span> </span><span class="code-line"><span class="token punctuation">[</span>root@HuangYeMacBookPro /<span class="token punctuation">]</span><span class="token comment"># setsebool -P samba_share_nfs=1</span> </span><span class="code-line">setsebool <span class="token variable parameter">-P</span> <span class="token variable assign-left">samba_export_all_ro</span><span class="token operator">=</span><span class="token number">1</span> <span class="token variable assign-left">samba_export_all_rw</span><span class="token operator">=</span><span class="token number">1</span> </span></code></pre></div><p>smb配置常见错误:</p><hr/><p>客户端输入正确的用户名和密码后提示没有权限. 查看服务端日志可见:</p><div class="relative"><pre><code class="code-highlight language-log"><span class="code-line"><span class="token number date">Jan 31</span> <span class="token number time">21:13:12</span> HuangYeMacBookPro<span class="token punctuation">.</span>padavan smbd<span class="token punctuation">[</span><span class="token number">85205</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number date">2020/01/31</span> <span class="token number time">21:13:12.887831</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">/</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">/</span>source3<span class="token operator">/</span>smbd<span class="token operator">/</span>uid<span class="token punctuation">.</span>c<span class="token operator">:</span><span class="token number">448</span><span class="token operator">(</span>change_to_user_internal<span class="token operator">)</span> </span><span class="code-line"><span class="token number date">Jan 31</span> <span class="token number time">21:13:12</span> HuangYeMacBookPro<span class="token punctuation">.</span>padavan smbd<span class="token punctuation">[</span><span class="token number">85205</span><span class="token punctuation">]</span><span class="token operator">:</span> change_to_user_internal<span class="token operator">:</span> chdir_current_service<span class="token operator">(</span><span class="token operator">)</span> failed<span class="token operator">!</span> </span></code></pre></div><p>问题的原因:smb用户对应的系统用户对于指定的共享目录没有访问权限.</p><hr/><p>smb 配置参考:</p><p>编辑 <code>/etc/samba/smb.conf</code>, 增加:</p><p>假设我们当前登录的用户是 <code>ttys3</code> :</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">winshare</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">comment</span> <span class="token punctuation">=</span> <span class="token attr-value value">Media share accessible by kvm win guest</span> </span><span class="code-line"> <span class="token attr-name key">path</span> <span class="token punctuation">=</span> <span class="token attr-value value">/home/ttys3/winshare</span> </span><span class="code-line"> <span class="token attr-name key">valid users</span> <span class="token punctuation">=</span> <span class="token attr-value value">ttys3</span> </span><span class="code-line"> <span class="token attr-name key">public</span> <span class="token punctuation">=</span> <span class="token attr-value value">no</span> </span><span class="code-line"> <span class="token attr-name key">writable</span> <span class="token punctuation">=</span> <span class="token attr-value value">yes</span> </span><span class="code-line"> <span class="token attr-name key">create mask</span> <span class="token punctuation">=</span> <span class="token attr-value value">0664</span> </span><span class="code-line"> <span class="token attr-name key">directory mask</span> <span class="token punctuation">=</span> <span class="token attr-value value">2775</span> </span><span class="code-line"> <span class="token attr-name key">force create mode</span> <span class="token punctuation">=</span> <span class="token attr-value value">0664</span> </span><span class="code-line"> <span class="token attr-name key">force directory mode</span> <span class="token punctuation">=</span> <span class="token attr-value value">2775</span> </span></code></pre></div><p>虽然 Linux 已经有 <code>ttys3</code> 这个用户了,但是samba里面有另一套用户权限控制机制(注意:samba用户一定要是已经存在的Linux用户), 但是我们还是要将这个用户添加进samba:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">smbpasswd <span class="token variable parameter">-a</span> ttys3 </span><span class="code-line"><span class="token comment"># 然后设置密码(注意这里的密钥是用于设置samba用户的密码,新设置的,并不是要你输入系统用户的)</span> </span></code></pre></div><hr/><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p>在 MacBook Air 上安装 Fedora 26 <a href="https://linux.cn/article-8690-1.html">https://linux.cn/article-8690-1.html</a></p><p><a href="http://blog.manton.im/2017/07/mac-book-air-installing-broadcom.html">http://blog.manton.im/2017/07/mac-book-air-installing-broadcom.html</a></p><p><a href="https://fedoraproject.org/wiki/GRUB_2?rd=Grub2#Updating_GRUB_2_configuration_on_UEFI_systems">https://fedoraproject.org/wiki/GRUB_2?rd=Grub2#Updating_GRUB_2_configuration_on_UEFI_systems</a></p><p>(Macbook Air)BCM4360网卡Linux(Ubuntu/Fedora)驱动安装总结 <a href="https://blog.csdn.net/zbjdonald/article/details/45015205">https://blog.csdn.net/zbjdonald/article/details/45015205</a></p><p><a href="https://rpmfusion.org/Configuration">https://rpmfusion.org/Configuration</a></p><p><a href="https://rpmfusion.org/Howto/NVIDIA">https://rpmfusion.org/Howto/NVIDIA</a></p><p>Fedora Linux – How to Use dnf Command With A Proxy Server <a href="https://www.cyberciti.biz/faq/how-to-use-dnf-command-with-a-proxy-server-on-fedora/">https://www.cyberciti.biz/faq/how-to-use-dnf-command-with-a-proxy-server-on-fedora/</a></p><p><a href="https://code.visualstudio.com/docs/setup/linux#_rhel-fedora-and-centos-based-distributions">https://code.visualstudio.com/docs/setup/linux#_rhel-fedora-and-centos-based-distributions</a></p><p><a href="https://docs.fedoraproject.org/en-US/fedora/f31/system-administrators-guide/servers/File_and_Print_Servers/">https://docs.fedoraproject.org/en-US/fedora/f31/system-administrators-guide/servers/File_and_Print_Servers/</a></p><p><a href="https://www.lisenet.com/2016/samba-server-on-rhel-7/">https://www.lisenet.com/2016/samba-server-on-rhel-7/</a></p><p><a href="https://www.hiroom2.com/2018/11/30/fedora-29-samba-en/">https://www.hiroom2.com/2018/11/30/fedora-29-samba-en/</a></p><p><a href="https://www.tecmint.com/install-samba4-on-centos-7-for-file-sharing-on-windows/">https://www.tecmint.com/install-samba4-on-centos-7-for-file-sharing-on-windows/</a></p><p><a href="https://wiki.archlinux.org/index.php/Samba">https://wiki.archlinux.org/index.php/Samba</a></p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/virtualization/sect-virtualization-security_for_virtualization-selinux_and_virtualization">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/virtualization/sect-virtualization-security_for_virtualization-selinux_and_virtualization</a></p><p><a href="https://wiki.archlinux.org/index.php/Fan_speed_control">https://wiki.archlinux.org/index.php/Fan_speed_control</a></p><p><a href="https://ineed.coffee/992/mbpfan-v1-4-0-is-out/">https://ineed.coffee/992/mbpfan-v1-4-0-is-out/</a></p><p><a href="https://ineed.coffee/projects/mbpfan/">https://ineed.coffee/projects/mbpfan/</a></p><p><a href="https://github.com/linux-on-mac/mbpfan">https://github.com/linux-on-mac/mbpfan</a></p><p><a href="https://docs.fedoraproject.org/en-US/quick-docs/creating-windows-virtual-machines-using-virtio-drivers/index.html">https://docs.fedoraproject.org/en-US/quick-docs/creating-windows-virtual-machines-using-virtio-drivers/index.html</a></p><p><a href="https://pve.proxmox.com/wiki/Windows_VirtIO_Drivers">https://pve.proxmox.com/wiki/Windows_VirtIO_Drivers</a></p><p><a href="https://github.com/virtio-win/kvm-guest-drivers-windows">https://github.com/virtio-win/kvm-guest-drivers-windows</a></p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/sect-managing_guest_virtual_machines_with_virsh-editing_a_guest_virtual_machines_configuration_file">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/sect-managing_guest_virtual_machines_with_virsh-editing_a_guest_virtual_machines_configuration_file</a></p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/virtualization/chap-virtualization-network_configuration#sect-Virtualization-Network_Configuration-Network_address_translation_NAT_with_libvirt">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/virtualization/chap-virtualization-network_configuration#sect-Virtualization-Network_Configuration-Network_address_translation_NAT_with_libvirt</a></p><p>KVM虚拟机网络配置方式 (Bridge方式 Nat方式) <a href="https://blog.csdn.net/weixin_36820871/article/details/80595855">https://blog.csdn.net/weixin_36820871/article/details/80595855</a></p> Thu, 04 Jun 2020 02:18:07 GMT ttyS3 macfedoratut https://ttys3.dev/blog/why-cgit-does-not-implement-fastcgi 为什么cgit不实现FastCGI https://ttys3.dev/blog/why-cgit-does-not-implement-fastcgi <h2 id="cgit简介"><a href="#cgit简介" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>cgit简介</h2><p>cgit - A hyperfast web frontend for git repositories written in C.</p><p><a href="https://git.zx2c4.com/cgit/about/">cgit</a>没有多余的功能,它就是一个简洁的Git WEB UI.</p><ul><li>basic repository browsing (logs, diffs, trees...)</li><li>caching of generated HTML</li><li>cloneable URLs (implements dumb HTTP transport)</li><li>commit feeds (atom format)</li><li>discovery of Git repositories</li><li>on-the-fly archives for tags and commits</li><li>plugin support for e.g. syntax highlighting</li><li>side-by-side diffs</li><li>simple time/author statistics</li><li>simple virtual hosting support (macro expansion)</li><li>understands GitWeb project-lists</li><li>understands gitweb.owner in Git config files</li><li>has extensive filtering framework using scripts or a built-in lua interpreter</li></ul><p>cgit 这个 WEB UI 本身没有授权验证功能,不过可以通过插件来实现。 cgit也没有仓库授权验证功能,一般可以通过配合<a href="https://github.com/sitaramc/gitolite">gitolite</a> 一起使用来实现。</p><p>从界面来说,cgit和git自带的<a href="https://github.com/git/git/tree/master/gitweb">Gitweb</a>非常像。</p><p>gitweb后端主要是一个perl文件 <a href="https://github.com/git/git/blob/master/gitweb/gitweb.perl">https://github.com/git/git/blob/master/gitweb/gitweb.perl</a> , 通过阅读这个文件不难发现,gitweb本身是直接通过调用git命令来实现功能的, 而cgit还是更加高效一些,因为它直接是在c层面调用git.</p><p>cgit和gitweb的关系:</p><p>cgit 0.1 是cgit的第一个版本,发布日期为<code>2006-12-21</code> ( <a href="https://git.zx2c4.com/cgit/tag/?h=v0.1">https://git.zx2c4.com/cgit/tag/?h=v0.1</a> )</p><p>根据<a href="https://github.com/git/git/blob/80659ff47bb0268af18925478053a82842a264a5/gitweb/README">gitweb的README</a>:</p><blockquote><p>From the git version 1.4.0 gitweb is bundled with git.</p></blockquote><p>git 1.4.0 是集成 gitweb 的第一个版本,发布日期为<code>Jun 11, 2006</code> ( <a href="https://github.com/git/git/releases/tag/v1.4.0">https://github.com/git/git/releases/tag/v1.4.0</a> )</p><p>所以,根据上面的发布信息,应该是先有gitweb,再有cgit. cgit第一版的发布日期,大概是gitweb发布的半年之后。可能是cgit作者觉得gitweb不好用,或者不太高效,因此才有了自己写cgit的想法吧。</p><p>因此,cgit主要适合用于托管开源代码,供人浏览代码和clone代码。</p><p>比如TI就有用cgit <a href="https://git.ti.com/cgit">https://git.ti.com/cgit</a></p><p>如果你需要更多的功能,可能你更适合<a href="https://github.com/go-gitea/gitea">gitea</a>或<a href="https://gitlab.com/gitlab-org/gitlab">gitlab社区版</a>之类的。</p><p>gitea主要是采用Golang编写,而gitlab似乎是遵循了传统,和Github一样采用了Ruby。</p><h2 id="cgit运行方式"><a href="#cgit运行方式" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>cgit运行方式</h2><p>cgit自身没有实现httpd server, 它只是一个遵循CGI规范的可执行文件加一些css和html.</p><p>需要配合http server(比如nginx或Caddy之类的)通过CGI调用的方式来运行。</p><p>熟悉WEB开发的应该都知道,像PHP之类的脚本语言解析器,基本上都是以FastCGI的方式 + nginx 来运行应用。而cgit为什么还在坚守古老的CGI协议呢?</p><p>对此,老灯也一直不解。直到有一天在一个mail list上看到了一个cgit项目的参与贡献者的回答。</p><p>为什么能证明是参与者?随便Google下关键字<strong>John Keeping+cgit</strong>,可以找到一些信息,比如 <a href="https://git.zx2c4.com/cgit/commit/ui-tree.c?id=985fba80d06f37fdba5e72d738ce21ab5ab5a76d">https://git.zx2c4.com/cgit/commit/ui-tree.c?id=985fba80d06f37fdba5e72d738ce21ab5ab5a76d</a> , 他是代码reviewer. <code>Reviewed-by: John Keeping &lt;[email protected]&gt;</code></p><p><a href="https://lists.zx2c4.com/pipermail/cgit/2013-April/001297.html">https://lists.zx2c4.com/pipermail/cgit/2013-April/001297.html</a> 内容如下:</p><p>John Keeping john at keeping.me.uk Sat Apr 13 11:34:10 CEST 2013</p><p>On Sat, Apr 13, 2013 at 01:51:03AM -0700, Peter Wu wrote:</p><blockquote><p>I am investigating the options for deploying cgit+gitolite. As I am running nginx, I have to use fastcgi or something similar.</p><p>Some resources that I found during a search:</p><ul><li><a href="http://russellhaering.com/2009/12/22/running-cgit-under-nginx/">http://russellhaering.com/2009/12/22/running-cgit-under-nginx/</a></li><li><a href="https://gist.github.com/stran12/1394757">https://gist.github.com/stran12/1394757</a></li><li><a href="http://polemon.org/cgit_nginx">http://polemon.org/cgit_nginx</a></li><li><a href="http://blog.zx2c4.com/293">http://blog.zx2c4.com/293</a></li></ul><p>Their instructions however, do suggest the use of nginx + spawn-cgi + fcgiwrap + cgit. I have some issues with it:</p><ul><li>Even if nginx and cgit run as different users, nginx can still run arbitrary commands under the rights of cgit (via SCRIPT_FILENAME).</li><li>If the only goal of fcgiwrap is to run cgit, why fcgiwrap at all and not integrate it into cgit?</li></ul><p>So I was wondering if somebody has already considered integrating fastcgi into cgit or other experiences with a nginx+(fastcgi+)cgit setup? I do not expect much traffic, but still want to have a secure (isolated) setup with predictable resource use.</p></blockquote><p>The problem with implementing FastCGI in CGit is that CGit currently relies on the OS cleaning up resources when the process exits. So if we use the same process for multiple requests it will just keep growing (in terms of memory use).</p><p>There has recently been some progress on improving the CGit side of this, but Git also takes this approach for repository objects.</p><p>In addition to that, Git isn&#x27;t designed for a process to work on more than one repository, so it would be difficult to make CGit handle multiple repositories in a single process correctly.</p><p>Given all of that, any implementation of FastCGI in CGit is going to look more or less the same as fcgiwrap, so I don&#x27;t see any reason not to just use that.</p><p>AFAICT, SCRIPT_FILENAME should be managed for you by the webserver and if you are using nginx then it can&#x27;t actually be used to run arbitrary commands [1]. But I&#x27;ve never use it so perhaps someone with experience of using CGit with nginx would like to comment here.</p><p>[1] <a href="http://nginx.localdomain.pl/wiki/FcgiWrap">http://nginx.localdomain.pl/wiki/FcgiWrap</a></p><p>简单来说就是由于cgit是严重依赖于git代码的,因此它的工作方式其实是跟git差不多。</p><p>如是你编译过cgit代码,你会发现它在编译前要下载一份完整的git源码,它自身的源码是直接依赖git源码的。所以cgit的版本是跟git版本大致绑定的。 所以这差不多14年来(2006-2020), cgit一直跟随git更新而更新。</p><p>要是cgit是采用<a href="https://github.com/libgit2/libgit2">libgit2</a>写的,肯定切换到FastCGI会没有什么难度, 但是由于历史原因,cgit已经是这样实现了,因此,不太可能会更换到FastCGI实现了。</p><p>最后,当然是要安利一波老灯的cgit docker镜像。</p><p>这可能是最用心的一个cgit镜像了 <a href="https://hub.docker.com/r/80x86/cgit">https://hub.docker.com/r/80x86/cgit</a> , 老灯历时三天三夜(是真的三天三夜时间,这不是台词)才完成。</p> Wed, 03 Jun 2020 17:52:23 GMT ttyS3 gitcgitCGIgit frontend https://ttys3.dev/blog/hugo-fast-search 5分钟给Hugo博客增加搜索功能 https://ttys3.dev/blog/hugo-fast-search <p>此方法来自<a href="https://gohugo.io/tools/search/">Hugo官方文档</a> 中的 <a href="https://gist.github.com/cmod/5410eae147e4318164258742dd053993">hugofastsearch</a></p><blockquote><p>A usability and speed update to “Github Gist for Fuse.js integration” — global, keyboard-optimized search.</p></blockquote><p>没错,这个方案,是<a href="https://gist.github.com/eddiewebb/735feb48f50f0ddd65ae5606a1cb41ae">Github Gist for Fuse.js integration</a> 的改进版。</p><p>其实在使用这个方案之前,老灯也尝试了<code>hugo-lunr-zh</code> 方案。<a href="https://www.npmjs.com/package/hugo-lunr">hugo-lunr</a> <strong>Last publish 4 years ago</strong> 而<a href="https://www.npmjs.com/package/hugo-lunr-zh">hugo-lunr-zh</a>本身是基于<code>hugo-lunr</code>添加了一个nodejieba(结巴分词lib)分词的功能以支持中文,同样是年久失修了 <strong>Last publish 2 years ago</strong>, 不过我使用这个生成索引失败了,没有任何错误输出,只能做罢。</p><h2 id="亮点"><a href="#亮点" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>亮点</h2><ol><li>最小/零外部依赖(无需jQuery)</li><li>添加到每个页面尺寸尽可能小</li><li>JSON索引文件按需加载(进一步减少对页的速度/用户体验的整体影响)</li><li>键盘友好,瞬时导航(有点像Alfred / macOS Spotlight)</li></ol><p>另外,此方案就像<a href="https://gist.github.com/eddiewebb/735feb48f50f0ddd65ae5606a1cb41ae">Eddie Webb指出的那样</a>, 还有如下额外的好处:</p><ol><li>无需NPM, grunt等外部工具</li><li>无需额外的编译步骤,你只需要像往常一样执行<code>hugo</code></li><li>可以方便地切换到任意可使用json索引的客户端搜索工具</li></ol><h2 id="集成步骤"><a href="#集成步骤" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>集成步骤</h2><ol><li>添加 <code>index.json</code> 文件到 <code>layouts/_default</code></li><li>修改<code>config.toml</code>以使Hugo对首页生成额外的<code>JSON</code>输出格式</li><li>添加<code>fastsearch.js</code> 和 <code>fuse.min.js</code> (可从 <a href="https://fusejs.io">https://fusejs.io</a> 下载) 到 <code>static/js</code></li><li>添加搜索框HTML代码到模板页面footer</li><li>添加CSS样式到模板页面header或模板主CSS文件</li><li>访问 <a href="http://localhost:1313/">http://localhost:1313/</a> , 键入 <code>Alt-/</code> 执行搜索</li></ol><h2 id="相关文件"><a href="#相关文件" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>相关文件</h2><blockquote><p>注意:跟原文章相比,老灯做了一些微调</p></blockquote><ol><li><p>允许通过点击页面空白处隐藏搜索框,而不是只能按Esc</p></li><li><p>在右上角添加了一个搜索按钮,方便不想按快捷键的人</p></li><li><p>默认的快捷键由于Firefox Linux默认 <code>Super-/</code>是 <strong>Quick Find</strong> 功能,因此我改成了 <code>Alt-/</code></p></li><li><p><code>layouts/_default/index.json</code></p></li></ol><div class="relative"><pre><code class="code-highlight language-go-html-template"><span class="code-line">{{- $.Scratch.Add &quot;index&quot; slice -}} </span><span class="code-line">{{- range .Site.RegularPages -}} </span><span class="code-line"> {{- $.Scratch.Add &quot;index&quot; (dict &quot;title&quot; .Title &quot;tags&quot; .Params.tags &quot;categories&quot; .Params.categories &quot;contents&quot; .Plain &quot;permalink&quot; .Permalink &quot;date&quot; .Date &quot;section&quot; .Section) -}} </span><span class="code-line">{{- end -}} </span><span class="code-line">{{- $.Scratch.Get &quot;index&quot; | jsonify -}} </span></code></pre></div><blockquote><p>这里默认取的<code>contents</code>, 如果文章数量特别多,可能会导致生成的索引过大</p></blockquote><ol start="2"><li><code>config.toml</code> 增加配置</li></ol><div class="relative"><pre><code class="code-highlight language-toml"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">outputs</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token property key">home</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">&quot;HTML&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;RSS&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;JSON&quot;</span><span class="token punctuation">]</span> </span></code></pre></div><ol start="3"><li><code>static/js/fastsearch.js</code></li></ol><p><code>fuse.min.js</code> 可从 <a href="https://github.com/krisk/Fuse/releases">https://github.com/krisk/Fuse/releases</a> 下载。</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token keyword">var</span> fuse<span class="token punctuation">;</span> <span class="token comment">// holds our search engine</span> </span><span class="code-line"><span class="token keyword">var</span> fuseIndex<span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">var</span> searchVisible <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token keyword">var</span> firstRun <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token comment">// allow us to delay loading json data unless search activated</span> </span><span class="code-line"><span class="token keyword">var</span> list <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">getElementById</span><span class="token punctuation">(</span><span class="token string">&#x27;searchResults&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// targets the &lt;ul&gt;</span> </span><span class="code-line"><span class="token keyword">var</span> first <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token property-access">firstChild</span><span class="token punctuation">;</span> <span class="token comment">// first child of search list</span> </span><span class="code-line"><span class="token keyword">var</span> last <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token property-access">lastChild</span><span class="token punctuation">;</span> <span class="token comment">// last child of search list</span> </span><span class="code-line"><span class="token keyword">var</span> maininput <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">getElementById</span><span class="token punctuation">(</span><span class="token string">&#x27;searchInput&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// input box for search</span> </span><span class="code-line"><span class="token keyword">var</span> resultsAvailable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token comment">// Did we get any search results?</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// ==========================================</span> </span><span class="code-line"><span class="token comment">// The main keyboard event listener running the show</span> </span><span class="code-line"><span class="token comment">//</span> </span><span class="code-line"><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">addEventListener</span><span class="token punctuation">(</span><span class="token string">&#x27;keydown&#x27;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// CMD-/ to show / hide Search</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">altKey</span> <span class="token operator">&amp;&amp;</span> event<span class="token punctuation">.</span><span class="token property-access">which</span> <span class="token operator">===</span> <span class="token number">191</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// Load json search index if first time invoking search</span> </span><span class="code-line"> <span class="token comment">// Means we don&#x27;t load json unless searches are going to happen; keep user payload small unless needed</span> </span><span class="code-line"> <span class="token function">doSearch</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// Allow ESC (27) to close search box</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">keyCode</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>searchVisible<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;fastSearch&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">style</span><span class="token punctuation">.</span><span class="token property-access">visibility</span> <span class="token operator">=</span> <span class="token string">&quot;hidden&quot;</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">activeElement</span><span class="token punctuation">.</span><span class="token property-access function method">blur</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> searchVisible <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// DOWN (40) arrow</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">keyCode</span> <span class="token operator">==</span> <span class="token number">40</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>searchVisible <span class="token operator">&amp;&amp;</span> resultsAvailable<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name console">console</span><span class="token punctuation">.</span><span class="token property-access function method">log</span><span class="token punctuation">(</span><span class="token string">&quot;down&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> event<span class="token punctuation">.</span><span class="token property-access function method">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// stop window from scrolling</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">activeElement</span> <span class="token operator">==</span> maininput<span class="token punctuation">)</span> <span class="token punctuation">{</span> first<span class="token punctuation">.</span><span class="token property-access function method">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// if the currently focused element is the main input --&gt; focus the first &lt;li&gt;</span> </span><span class="code-line"> <span class="token keyword control-flow">else</span> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">activeElement</span> <span class="token operator">==</span> last <span class="token punctuation">)</span> <span class="token punctuation">{</span> last<span class="token punctuation">.</span><span class="token property-access function method">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// if we&#x27;re at the bottom, stay there</span> </span><span class="code-line"> <span class="token keyword control-flow">else</span> <span class="token punctuation">{</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">activeElement</span><span class="token punctuation">.</span><span class="token property-access">parentElement</span><span class="token punctuation">.</span><span class="token property-access">nextSibling</span><span class="token punctuation">.</span><span class="token property-access">firstElementChild</span><span class="token punctuation">.</span><span class="token property-access function method">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// otherwise select the next search result</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">// UP (38) arrow</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">keyCode</span> <span class="token operator">==</span> <span class="token number">38</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>searchVisible <span class="token operator">&amp;&amp;</span> resultsAvailable<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> event<span class="token punctuation">.</span><span class="token property-access function method">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// stop window from scrolling</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">activeElement</span> <span class="token operator">==</span> maininput<span class="token punctuation">)</span> <span class="token punctuation">{</span> maininput<span class="token punctuation">.</span><span class="token property-access function method">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// If we&#x27;re in the input box, do nothing</span> </span><span class="code-line"> <span class="token keyword control-flow">else</span> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">activeElement</span> <span class="token operator">==</span> first<span class="token punctuation">)</span> <span class="token punctuation">{</span> maininput<span class="token punctuation">.</span><span class="token property-access function method">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// If we&#x27;re at the first item, go to input box</span> </span><span class="code-line"> <span class="token keyword control-flow">else</span> <span class="token punctuation">{</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">activeElement</span><span class="token punctuation">.</span><span class="token property-access">parentElement</span><span class="token punctuation">.</span><span class="token property-access">previousSibling</span><span class="token punctuation">.</span><span class="token property-access">firstElementChild</span><span class="token punctuation">.</span><span class="token property-access function method">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Otherwise, select the search result above the current active one</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// ==========================================</span> </span><span class="code-line"><span class="token comment">// execute search as each character is typed</span> </span><span class="code-line"><span class="token comment">//</span> </span><span class="code-line"><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;searchInput&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access function method function-variable method-variable">onkeyup</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">executeSearch</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token property-access">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;body&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access function method function-variable method-variable">onclick</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">tagName</span> <span class="token operator">===</span> <span class="token string">&#x27;BODY&#x27;</span> <span class="token operator">||</span> e<span class="token punctuation">.</span><span class="token property-access">target</span><span class="token punctuation">.</span><span class="token property-access">tagName</span> <span class="token operator">===</span> <span class="token string">&#x27;DIV&#x27;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">hideSearch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;#search-btn&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access function method function-variable method-variable">onclick</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">doSearch</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">function</span> <span class="token function">doSearch</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> e<span class="token punctuation">.</span><span class="token property-access function method">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>firstRun<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">loadSearch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// loads our json data and builds fuse.js search index</span> </span><span class="code-line"> firstRun <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token comment">// let&#x27;s never do this again</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token comment">// Toggle visibility of search box</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>searchVisible<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">showSearch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// search visible</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword control-flow">else</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">hideSearch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">function</span> <span class="token function">hideSearch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;fastSearch&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">style</span><span class="token punctuation">.</span><span class="token property-access">visibility</span> <span class="token operator">=</span> <span class="token string">&quot;hidden&quot;</span> <span class="token comment">// hide search box</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access">activeElement</span><span class="token punctuation">.</span><span class="token property-access function method">blur</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// remove focus from search box </span> </span><span class="code-line"> searchVisible <span class="token operator">=</span> <span class="token boolean">false</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">function</span> <span class="token function">showSearch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;fastSearch&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">style</span><span class="token punctuation">.</span><span class="token property-access">visibility</span> <span class="token operator">=</span> <span class="token string">&quot;visible&quot;</span> <span class="token comment">// show search box</span> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;searchInput&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access function method">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// put focus in input box so you can just start typing</span> </span><span class="code-line"> searchVisible <span class="token operator">=</span> <span class="token boolean">true</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// ==========================================</span> </span><span class="code-line"><span class="token comment">// fetch some json without jquery</span> </span><span class="code-line"><span class="token comment">//</span> </span><span class="code-line"><span class="token keyword">function</span> <span class="token function">fetchJSONFile</span><span class="token punctuation">(</span><span class="token parameter">path<span class="token punctuation">,</span> callback</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">var</span> httpRequest <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> httpRequest<span class="token punctuation">.</span><span class="token property-access function method function-variable method-variable">onreadystatechange</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>httpRequest<span class="token punctuation">.</span><span class="token property-access">readyState</span> <span class="token operator">===</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>httpRequest<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> <span class="token number">200</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">var</span> data <span class="token operator">=</span> <span class="token class-name known-class-name">JSON</span><span class="token punctuation">.</span><span class="token property-access function method">parse</span><span class="token punctuation">(</span>httpRequest<span class="token punctuation">.</span><span class="token property-access">responseText</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>callback<span class="token punctuation">)</span> <span class="token function">callback</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> httpRequest<span class="token punctuation">.</span><span class="token property-access function method">open</span><span class="token punctuation">(</span><span class="token string">&#x27;GET&#x27;</span><span class="token punctuation">,</span> path<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> httpRequest<span class="token punctuation">.</span><span class="token property-access function method">send</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// ==========================================</span> </span><span class="code-line"><span class="token comment">// load our search index, only executed once</span> </span><span class="code-line"><span class="token comment">// on first call of search box (CMD-/)</span> </span><span class="code-line"><span class="token comment">//</span> </span><span class="code-line"><span class="token keyword">function</span> <span class="token function">loadSearch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token class-name console">console</span><span class="token punctuation">.</span><span class="token property-access function method">log</span><span class="token punctuation">(</span><span class="token string">&#x27;loadSearch()&#x27;</span><span class="token punctuation">)</span> </span><span class="code-line"> <span class="token function">fetchJSONFile</span><span class="token punctuation">(</span><span class="token string">&#x27;/index.json&#x27;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span><span class="token punctuation">{</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword">var</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">// fuse.js options; check fuse.js website for details</span> </span><span class="code-line"> <span class="token property literal-property">shouldSort</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property literal-property">location</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property literal-property">distance</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property literal-property">threshold</span><span class="token operator">:</span> <span class="token number">0.4</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property literal-property">minMatchCharLength</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property literal-property">keys</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&#x27;permalink&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&#x27;title&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&#x27;tags&#x27;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token string">&#x27;contents&#x27;</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment">// Create the Fuse index</span> </span><span class="code-line"> fuseIndex <span class="token operator">=</span> <span class="token maybe-class-name">Fuse</span><span class="token punctuation">.</span><span class="token property-access function method">createIndex</span><span class="token punctuation">(</span>options<span class="token punctuation">.</span><span class="token property-access">keys</span><span class="token punctuation">,</span> data<span class="token punctuation">)</span> </span><span class="code-line"> fuse <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Fuse</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> options<span class="token punctuation">,</span> fuseIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// build the index from the json file</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// ==========================================</span> </span><span class="code-line"><span class="token comment">// using the index we loaded on CMD-/, run </span> </span><span class="code-line"><span class="token comment">// a search query (for &quot;term&quot;) every time a letter is typed</span> </span><span class="code-line"><span class="token comment">// in the search box</span> </span><span class="code-line"><span class="token comment">//</span> </span><span class="code-line"><span class="token keyword">function</span> <span class="token function">executeSearch</span><span class="token punctuation">(</span><span class="token parameter">term</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword">let</span> results <span class="token operator">=</span> fuse<span class="token punctuation">.</span><span class="token property-access function method">search</span><span class="token punctuation">(</span>term<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// the actual query being run using fuse.js</span> </span><span class="code-line"> <span class="token keyword">let</span> searchitems <span class="token operator">=</span> <span class="token string">&#x27;&#x27;</span><span class="token punctuation">;</span> <span class="token comment">// our results bucket</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>results<span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// no results based on what was typed into the input box</span> </span><span class="code-line"> resultsAvailable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> </span><span class="code-line"> searchitems <span class="token operator">=</span> <span class="token string">&#x27;&#x27;</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> <span class="token keyword control-flow">else</span> <span class="token punctuation">{</span> <span class="token comment">// build our html</span> </span><span class="code-line"> <span class="token comment">// console.log(results)</span> </span><span class="code-line"> permalinks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> </span><span class="code-line"> numLimit <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword control-flow">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> item <span class="token keyword">in</span> results<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// only show first 5 results</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>item <span class="token operator">&gt;</span> numLimit<span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">break</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>permalinks<span class="token punctuation">.</span><span class="token property-access function method">includes</span><span class="token punctuation">(</span>results<span class="token punctuation">[</span>item<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token property-access">item</span><span class="token punctuation">.</span><span class="token property-access">permalink</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token keyword control-flow">continue</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token comment">// console.log(&#x27;item: %d, title: %s&#x27;, item, results[item].item.title)</span> </span><span class="code-line"> searchitems <span class="token operator">=</span> searchitems <span class="token operator">+</span> <span class="token string">&#x27;&lt;li&gt;&lt;a href=&quot;&#x27;</span> <span class="token operator">+</span> results<span class="token punctuation">[</span>item<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token property-access">item</span><span class="token punctuation">.</span><span class="token property-access">permalink</span> <span class="token operator">+</span> <span class="token string">&#x27;&quot; tabindex=&quot;0&quot;&gt;&#x27;</span> <span class="token operator">+</span> <span class="token string">&#x27;&lt;span class=&quot;title&quot;&gt;&#x27;</span> <span class="token operator">+</span> results<span class="token punctuation">[</span>item<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token property-access">item</span><span class="token punctuation">.</span><span class="token property-access">title</span> <span class="token operator">+</span> <span class="token string">&#x27;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&#x27;</span><span class="token punctuation">;</span> </span><span class="code-line"> permalinks<span class="token punctuation">.</span><span class="token property-access function method">push</span><span class="token punctuation">(</span>results<span class="token punctuation">[</span>item<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token property-access">item</span><span class="token punctuation">.</span><span class="token property-access">permalink</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> resultsAvailable <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token property-access function method">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;searchResults&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access">innerHTML</span> <span class="token operator">=</span> searchitems<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>results<span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> first <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token property-access">firstChild</span><span class="token punctuation">.</span><span class="token property-access">firstElementChild</span><span class="token punctuation">;</span> <span class="token comment">// first result container — used for checking against keyboard up/down location</span> </span><span class="code-line"> last <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token property-access">lastChild</span><span class="token punctuation">.</span><span class="token property-access">firstElementChild</span><span class="token punctuation">;</span> <span class="token comment">// last result container — used for checking against keyboard up/down location</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><ol start="4"><li>添加搜索框HTML代码到模板页面footer</li></ol><p>这个可以通过添加到 baseof 或者 footer 模板。</p><p>比如我当前在使用的<a href="https://github.com/ttys3/hugo-theme-terminal/tree/ttys3">terminal</a>主题, 它就内置了额外的footer支持, 可以通过添加 <code>layouts/partials/extended_footer.html</code> 方便地对footer增加内容。</p><p>如果主题没有额外的支持,你可以copy你当前主题目录下的baseof.html模板到<code>layouts/_default/baseof.html</code>,然后在最后附加内容。</p><div class="relative"><pre><code class="code-highlight language-html"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>search-btn<span class="token punctuation">&quot;</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token language-css css value"><span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span></span><span class="token punctuation">&quot;</span></span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>javascript:void(0);<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>icon-search<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>捜<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>fastSearch<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>searchInput<span class="token punctuation">&quot;</span></span> <span class="token attr-name">tabindex</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>0<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>searchResults<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>/js/fuse.min.js<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span> <span class="token comment">&lt;!-- download and copy over fuse.min.js file from fusejs.io --&gt;</span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>/js/fastsearch.js<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><ol start="5"><li>添加CSS样式到模板页面header或模板主CSS文件</li></ol><p>这个可以通过添加到 header 模板 或模板的主CSS文件。</p><p>比如我当前在使用的<a href="https://github.com/ttys3/hugo-theme-terminal/tree/ttys3">terminal</a>主题, 它就内置了额外的header支持, 可以通过添加 <code>layouts/partials/extended_header.html</code> 方便地对header增加内容。</p><p>如果主题没有额外的支持,你可以修改模板的主CSS文件,通常是<code>style.css</code> 或 <code>main.css</code>, 这个因情况而异。</p><div class="relative"><pre><code class="code-highlight language-css"><span class="code-line"> <span class="token selector"><span class="token id">#fastSearch</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">visibility</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">right</span><span class="token punctuation">:</span> <span class="token number">10</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">top</span><span class="token punctuation">:</span> <span class="token number">10</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">320</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span> <span class="token number">10</span><span class="token unit">px</span> <span class="token number">0</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token selector"><span class="token id">#fastSearch</span> input</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">4</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">100</span><span class="token unit">%</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">31</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">1.6</span><span class="token unit">em</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token color hexcode">#222129</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">font-weight</span><span class="token punctuation">:</span> bold<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token color hexcode">#ffa86a</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">3</span><span class="token unit">px</span> <span class="token number">3</span><span class="token unit">px</span> <span class="token number">0</span><span class="token unit">px</span> <span class="token number">0</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">outline</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">text-align</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token selector"><span class="token id">#searchResults</span> li</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">list-style</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">margin-left</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token unit">em</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token color hexcode">#333</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">border-bottom</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">px</span> dotted <span class="token color hexcode">#000</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token selector"><span class="token id">#searchResults</span> li <span class="token class">.title</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">1.1</span><span class="token unit">em</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token selector"><span class="token id">#searchResults</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">visibility</span><span class="token punctuation">:</span> inherit<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">320</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">max-height</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token unit">vh</span> <span class="token operator">-</span> <span class="token number">120</span><span class="token unit">px</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token selector"><span class="token id">#searchResults</span> a</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">text-decoration</span><span class="token punctuation">:</span> none <span class="token important">!important</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">10</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">100</span><span class="token unit">%</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token selector"><span class="token id">#searchResults</span> a<span class="token pseudo-class">:hover</span><span class="token punctuation">,</span> <span class="token id">#searchResults</span> a<span class="token pseudo-class">:focus</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">outline</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token color hexcode">#666</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token color hexcode">#fff</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token selector"><span class="token id">#search-btn</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">top</span><span class="token punctuation">:</span> <span class="token number">10</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">right</span><span class="token punctuation">:</span> <span class="token number">20</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token number">24</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span><span class="token number">683</span><span class="token unit">px</span><span class="token punctuation">)</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token selector"><span class="token id">#fastSearch</span><span class="token punctuation">,</span> <span class="token id">#search-btn</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">top</span><span class="token punctuation">:</span> <span class="token number">64</span><span class="token unit">px</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span></code></pre></div><p>如果样式跟你当前的主题不是很合,你可以自行稍作调整。</p> Wed, 03 Jun 2020 10:49:49 GMT ttyS3 Hugo https://ttys3.dev/blog/qt5-qdebug-troubleshoot-under-fedora32-centos8 Fedora 32/CentOS 8 下面Qt5 qDebug不输出的解决办法 https://ttys3.dev/blog/qt5-qdebug-troubleshoot-under-fedora32-centos8 <h2 id="解决办法"><a href="#解决办法" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>解决办法</h2><p>环境:</p><p><code>qt5-qtbase-devel</code> <code>5.13.2</code> @ Fedora 32 Workstation Edition</p><p><code>qt5-qtbase-devel</code> <code>5.11.1</code> @ CentOS Linux release 8.1.1911</p><p>首先检查<code>CONFIG</code>是不是包含<code>console</code>, 如果没有则加上 <code>CONFIG += console</code></p><p>检查<code>$HOME/.config/QtProject/qtlogging.ini</code>文件(如果没有则创建)是否包含以下内容:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"> <span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Rules</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">*.debug</span><span class="token punctuation">=</span><span class="token attr-value value">true</span> </span><span class="code-line"> <span class="token attr-name key">qt.*.debug</span><span class="token punctuation">=</span><span class="token attr-value value">false</span> </span></code></pre></div><p>重新运行Qt程序,就可以看到qDebug的输出了。</p><p>如果需要变成全局配置,可以修改文件<code>/etc/xdg/QtProject/qtlogging.ini</code>(没有则自行创建)。</p><h2 id="原因分析"><a href="#原因分析" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>原因分析</h2><p>这个问题可能是RHEL系里独有的, 至少我以前在<code>ArchLinux</code>下调试 qt5 程序时没有遇到过这个问题。</p><p>有一个bug报告是跟这个问题相关的 <a href="https://bugzilla.redhat.com/show_bug.cgi?id=1227295">https://bugzilla.redhat.com/show_bug.cgi?id=1227295</a></p><p>事实上本文上面的解决办法来自<a href="https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c10">第10条评论</a></p><p><a href="https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c15">第15楼</a>也很有料,根据他提供的 链接: <a href="http://pkgs.fedoraproject.org/cgit/rpms/qt5-qtbase.git/commit/?id=a09edb40e5587bd34d73aaec637d89d049ebbb0e">http://pkgs.fedoraproject.org/cgit/rpms/qt5-qtbase.git/commit/?id=a09edb40e5587bd34d73aaec637d89d049ebbb0e</a> 老灯发现,这个commit里,Fedora的<code>qt5-qtbase</code>包默认ship了一个配置<code>%{_qt5_datadir}/qtlogging.ini</code>, 其中包含一条禁用debug的规则(<code>*.debug=false</code>),并带上了注释:</p><blockquote><p>distro defaults, see also <a href="https://bugzilla.redhat.com/show_bug.cgi?id=1227295">https://bugzilla.redhat.com/show_bug.cgi?id=1227295</a> can override in <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><mi>D</mi><msub><mi>G</mi><mi>C</mi></msub><mi>O</mi><mi>N</mi><mi>F</mi><mi>I</mi><msub><mi>G</mi><mi>H</mi></msub><mi>O</mi><mi>M</mi><mi>E</mi><mi mathvariant="normal">/</mi><mi>Q</mi><mi>t</mi><mi>P</mi><mi>r</mi><mi>o</mi><mi>j</mi><mi>e</mi><mi>c</mi><mi>t</mi><mi mathvariant="normal">/</mi><mi>q</mi><mi>t</mi><mi>l</mi><mi>o</mi><mi>g</mi><mi>g</mi><mi>i</mi><mi>n</mi><mi>g</mi><mi mathvariant="normal">.</mi><mi>i</mi><mi>n</mi><mi>i</mi><mi>o</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">XDG_CONFIG_HOME/QtProject/qtlogging.ini or </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-.25em"></span><span class="mord mathnormal" style="margin-right:.07847em">X</span><span class="mord mathnormal" style="margin-right:.02778em">D</span><span class="mord"><span class="mord mathnormal">G</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:.3283em"><span style="top:-2.55em;margin-left:0;margin-right:.05em"><span class="pstrut" style="height:2.7em"></span><span class="mtight reset-size6 size3 sizing"><span class="mord mathnormal mtight" style="margin-right:.07153em">C</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:.15em"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:.13889em">ONF</span><span class="mord mathnormal" style="margin-right:.07847em">I</span><span class="mord"><span class="mord mathnormal">G</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:.3283em"><span style="top:-2.55em;margin-left:0;margin-right:.05em"><span class="pstrut" style="height:2.7em"></span><span class="mtight reset-size6 size3 sizing"><span class="mord mathnormal mtight" style="margin-right:.08125em">H</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:.15em"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:.05764em">OME</span><span class="mord">/</span><span class="mord mathnormal" style="margin-right:.13889em">QtP</span><span class="mord mathnormal">ro</span><span class="mord mathnormal" style="margin-right:.05724em">j</span><span class="mord mathnormal">ec</span><span class="mord mathnormal">t</span><span class="mord">/</span><span class="mord mathnormal" style="margin-right:.01968em">qtl</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:.03588em">gg</span><span class="mord mathnormal">in</span><span class="mord mathnormal" style="margin-right:.03588em">g</span><span class="mord">.</span><span class="mord mathnormal">ini</span><span class="mord mathnormal" style="margin-right:.02778em">or</span></span></span></span></span>XDG_CONFIG_DIR/QtProject/qtlogging.ini</p></blockquote><p>即一般情况下,可通过<code>$HOME/.config/QtProject/qtlogging.ini</code> 或 <code>/etc/xdg/QtProject/qtlogging.ini</code> 来override这个配置。</p><p><a href="https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c29">29楼</a>同样很优秀啊,给出一个非常实用的tips</p><blockquote><p><code>QT_LOGGING_DEBUG=1</code> causes loadRulesFromFile to show files loaded</p></blockquote><p>尝试一下, 发现果然显示了这些rules来自哪些文件:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">QT_LOGGING_DEBUG</span><span class="token operator">=</span><span class="token number">1</span> </span><span class="code-line"> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">QT_MESSAGE_PATTERN</span><span class="token operator">=</span><span class="token string">&#x27;%{function}: %{message}&#x27;</span> </span><span class="code-line"> </span><span class="code-line">❯ ./dukto </span><span class="code-line">loadRulesFromFile: Loading <span class="token string">&quot;/usr/share/qt5/qtlogging.ini&quot;</span> <span class="token punctuation">..</span>. </span><span class="code-line">loadRulesFromFile: Loading <span class="token string">&quot;/etc/xdg/QtProject/qtlogging.ini&quot;</span> <span class="token punctuation">..</span>. </span><span class="code-line">main: os: linux </span><span class="code-line">main: setActivationWindow </span><span class="code-line">main: showExpanded </span><span class="code-line">main: installEventFilter </span><span class="code-line">GuiBehind::eventFilter: GuiBehind::eventFilter<span class="token punctuation">(</span><span class="token punctuation">)</span>: application activate sayHello </span><span class="code-line">GuiBehind::close: application activate sayGoodbye </span></code></pre></div><p>从上面可看到,在Fedora 32下, qt5 默认先加载<code>/usr/share/qt5/qtlogging.ini</code>, 我们看看这个文件内容:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">cat</span> /usr/share/qt5/qtlogging.ini </span><span class="code-line"><span class="token punctuation">[</span>Rules<span class="token punctuation">]</span> </span><span class="code-line">*.debug<span class="token operator">=</span>false </span><span class="code-line"><span class="token assign-left variable">qt.qpa.xcb.xcberror.warning</span><span class="token operator">=</span>false </span></code></pre></div><p>不但禁用了所有debug日志,还同时屏蔽了xcb QPA (Qt Platform Abstraction) platform plugin warning信息.</p><p>什么是xcb? <a href="https://doc.qt.io/qt-5/linux-requirements.html">https://doc.qt.io/qt-5/linux-requirements.html</a></p><blockquote><p>On Linux, the xcb QPA (Qt Platform Abstraction) platform plugin is used. It provides the basic functionality needed by Qt GUI and Qt Widgets to run against X11. Its library dependencies are described the following table. To build Qt from its source code, you will also need to install the development packages for these libraries for your system.</p></blockquote><p>注意xcb是只针对<code>X11</code>的,如果是<code>Wayland</code> 情况又不同了。需要 <a href="https://wiki.qt.io/QtWayland">QtWayland</a></p><blockquote><p>What is QtWayland? QtWayland is a Qt 5 module that wraps the functionality of Wayland. QtWayland is separated into a client and server side. The client side is the wayland platform plugin, and provides a way to run Qt applications as Wayland clients. The server side is the Qt Wayland Compositor API, and allows users to write their own Wayland compositors.</p></blockquote><p>老灯之所以还在用<code>X11</code>, 完全是因为NVIDIA显卡的官方驱动目前对于<code>Wayland</code>的支持不好。</p><p>如果查看下udev规则,就会发现Fedora 32目前为止都是默认为gdm禁用了Wayland:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ bat /usr/lib/udev/rules.d/61-gdm.rules </span><span class="code-line"><span class="token comment"># disable Wayland on Hi1710 chipsets</span> </span><span class="code-line">ATTR<span class="token punctuation">{</span>vendor<span class="token punctuation">}</span><span class="token operator">==</span><span class="token string">&quot;0x19e5&quot;</span>, ATTR<span class="token punctuation">{</span>device<span class="token punctuation">}</span><span class="token operator">==</span><span class="token string">&quot;0x1711&quot;</span>, <span class="token assign-left variable">RUN</span><span class="token operator">+=</span><span class="token string">&quot;/usr/libexec/gdm-disable-wayland&quot;</span> </span><span class="code-line"><span class="token comment"># disable Wayland when using the proprietary nvidia driver</span> </span><span class="code-line"><span class="token assign-left variable">DRIVER</span><span class="token operator">==</span><span class="token string">&quot;nvidia&quot;</span>, <span class="token assign-left variable">RUN</span><span class="token operator">+=</span><span class="token string">&quot;/usr/libexec/gdm-disable-wayland&quot;</span> </span><span class="code-line"><span class="token comment"># disable Wayland if modesetting is disabled</span> </span><span class="code-line">IMPORT<span class="token punctuation">{</span>cmdline<span class="token punctuation">}</span><span class="token operator">=</span><span class="token string">&quot;nomodeset&quot;</span>, <span class="token assign-left variable">RUN</span><span class="token operator">+=</span><span class="token string">&quot;/usr/libexec/gdm-disable-wayland&quot;</span> </span></code></pre></div><p>从上面可看出,只要用了the proprietary nvidia driver 或 内核禁用了<code>modeset</code>,这个规则都会禁用<code>Wayland</code>。 好吧,有点跑题了,打住。</p><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://stackoverflow.com/questions/12799653/qdebug-not-displaying-anything/50650124#50650124">https://stackoverflow.com/questions/12799653/qdebug-not-displaying-anything/50650124#50650124</a></p><p><a href="https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c10">https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c10</a></p><p><a href="https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c15">https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c15</a></p><p><a href="https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c29">https://bugzilla.redhat.com/show_bug.cgi?id=1227295#c29</a></p> Tue, 02 Jun 2020 17:04:40 GMT ttyS3 FedoraCentOS8Qt5qDebugtroubleshoot https://ttys3.dev/blog/how-to-deploy-private-repo-to-netlify Hugo如何将私有仓库发布到Netlify https://ttys3.dev/blog/how-to-deploy-private-repo-to-netlify <p>私有仓库发布跟public仓库稍有不同。增加了两步。这里记录一下。</p><h2 id="1-登录netlify生成deploy-key"><a aria-hidden="true" href="#1-登录netlify生成deploy-key" tabindex="-1"><span class="icon icon-link"></span></a>1. 登录Netlify生成deploy key</h2><p>登录Netlify, 点击进入要设置的站点,然后点击<code>Site settings</code>按钮, 然后点击<code>Build &amp; deploy</code>, 在<code>Continuous Deployment</code>下面,往下拖页面到<code>Deploy key</code>, 这里默认是没有key的,点击 <code>Generate public deploy key</code>生成一个deploy(发布)公钥。然后你会看到一个文本框,里面有rsa public key. 先复制完整的key内容到系统剪切板。</p><div><img alt="" src="https://ttys3.dev/static/assets/netlify-gen-deploy-key-2020-06-01-19-59-23-YSFJ7B6U.png" width="1924" height="688"/></div><blockquote><p>这里实际上Netlify会自动生成一个rsa密钥对,然后把public key(公钥)显示给你。至于私钥的内容,你不必关注,因为你不需要用到。</p></blockquote><h2 id="2-登录hugo源码托管仓库添加生成的deploy-key"><a aria-hidden="true" href="#2-登录hugo源码托管仓库添加生成的deploy-key" tabindex="-1"><span class="icon icon-link"></span></a>2. 登录Hugo源码托管仓库添加生成的deploy key</h2><p>这里以Github为例,进入Github对应的Hugo博客源码仓库,点击<code>Settings</code>进入仓库设置。选择<code>Deploy keys</code>,然后点击<code>Add deploy key</code> 按钮,把之前复制的key粘贴到<code>Key</code>文本框,Title的话自己填写上一个比较有意义点的名字吧,比如<strong>netlify-pull</strong>之类的。</p><div><img alt="" src="https://ttys3.dev/static/assets/github-config-deploy-key-2020-06-01-20-01-33-4C3MI5UO.png" width="1934" height="724"/></div><p>注意:</p><blockquote><p>Deploy keys always have pull access.</p></blockquote><p>即这个key默认是有pull权限的,对于将Hugo博客部署到Netlify而方,Netlify只是需要pull仓库而已,它并不需要push操作, 所以,这里我们并不需要勾选<code>Allow write access</code>. 基于最小权限原则,我们只给Netlify分配 一个<code>Read-only</code>的Deploy key.</p><p>OK了,大功造成。就这样。</p> Mon, 01 Jun 2020 11:41:11 GMT ttyS3 Hugonetlifyprivate repodeploy https://ttys3.dev/blog/why-firefox-option-background-color-do-not-work-under-linux 为什么 Firefox option 的 background-color 样式在 Linux 下不工作 https://ttys3.dev/blog/why-firefox-option-background-color-do-not-work-under-linux <p>系统版本: <code>Fedora 32</code> Firefox版本: <code>76.0.1 (64-bit)</code></p><p>我偶然发现一个页面bug。Chromium下是显示正常的:</p><div><img alt="" src="https://ttys3.dev/static/assets/option-background-color-chromium-67UG7MXG.jpg" width="360" height="366"/></div><p>而Firefox下是这样的:</p><div><img alt="" src="https://ttys3.dev/static/assets/option-background-color-firefox-linux-2DACUSJM.jpg" width="360" height="366"/></div><p>这个HTML代码看上去是没问题的:</p><div class="relative"><pre><code class="language-html code-highlight"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token css language-css value"><span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token color">black</span></span><span class="token punctuation">&quot;</span></span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>Black<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Black<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>option</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token css language-css value"><span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token color">sienna</span></span><span class="token punctuation">&quot;</span></span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>Sienna<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Sienna<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>option</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>然而<code>background-color</code>样式在Firefox下没有生效。</p><p>然后进行了一番搜索。</p><p>发现Firefox曾经确实是有这个bug <code>[e10s]</code> Properly style <code>&lt;option&gt;</code> elements in the parent process UI (support color and background on select options)</p><p><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=910022">https://bugzilla.mozilla.org/show_bug.cgi?id=910022</a></p><p>首先,这个bug前面有个奇怪的<code>e10s</code>, 这个<code>e10s</code>老灯可是从来没听过,是什么意思呢? 然后发现它官方博客有解释 <a href="https://blog.mozilla.org/addons/2016/04/11/the-why-of-electrolysis/">https://blog.mozilla.org/addons/2016/04/11/the-why-of-electrolysis/</a></p><p>原来在之前,Firefox一直是单进程的,在眼看着 IE8, Chrome 和 Safari 都相继转变成多进程后,Firefox意识到也需要进行这一转变。</p><p>而这个<strong>多进程架构</strong>的开发<strong>代号</strong>,就叫 <code>Electrolysis</code>, 简称<code>e10s</code>(这是惯用命名了,类似的例子比如l10n, i18n, k8s), e 和 s 之间隔着10个字母。</p><p>从这个bugzilla页面看,这个早在<code>firefox54</code>时就修复了啊。我现在用的是76了,怎么还有这个bug?</p><p>终于在so找到个答案: <a href="https://stackoverflow.com/questions/47401091/why-is-firefox-57-not-styling-my-option-elements-like-other-browsers/47401425#47401425">https://stackoverflow.com/questions/47401091/why-is-firefox-57-not-styling-my-option-elements-like-other-browsers/47401425#47401425</a></p><p>原来真正的答案在MDN <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option#Browser_compatibility">https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option#Browser_compatibility</a></p><p>最底下,Browser compatibility 那里,有个下三角默认是折叠的(非常隐蔽,可以说,要不是stackoverflow上有人告诉我,基本上可能没机会看到)。</p><p>关键是这一句:</p><blockquote><p>When Mozilla introduced dedicated content threads to Firefox (through the Electrolysis, or <code>e10s</code>, project), support for styling <code>&lt;option&gt;</code> elements was removed temporarily. Starting in Firefox 54, you can apply foreground and background colors to <code>&lt;option&gt;</code> elements again, using the <code>color</code> and <code>background-color</code> CSS properties. See <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=910022">bug 910022</a> for more information. Note that <strong>this is still disabled in Linux due to lack of contrast</strong> (see <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1338283">bug 1338283</a> for progress on this).</p></blockquote><p>也就是说,虽然在Firefox 54 <code>&lt;option&gt;</code>的 <code>color</code> 和 <code>background-color</code> 就恢复正常工作了,但是在Linux版本的Firefox上,这两个属性依然是禁用的。 (由于<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1338283">bug 1338283</a>)</p><p>现在已经是2020年了, 距离 <code>e10s</code> 已经 7年了, 距离<strong>bug 1338283</strong>被提出也已经3年了( Bug 1338283 Opened 3 years ago Updated 7 months ago ), 从Firefox54到现在Firefox71了还没修复Orz</p><p>Windows已经有基于Chromium内核的Edge了并且很好用了, 我相信大多数Windows用户应该没有太多理由再去用Chrome了(不开proxy连同步都不能工作), 更没有很好地理由来用Firefox.</p><p>而Mac默认已经内置了Safari, 即使用户不喜欢,大多数人很可能也是选择Chrome.</p><p>留给Linux用户的选择并不多,不能选Edge也不能选Safari,至少截止到目前,这两个浏览器都没有发布Linux版本。所以Linux要么选择Chromium(或闭源的Chrome), 要么选择Firefox.</p><p>其它小众浏览器这里不讨论。</p><p>像Fedora这种发行版,默认内置的浏览器就是Firefox. 因此, Firefox假如还没看清它真正的用户在哪里,我觉得有点替它担忧。 几年之后,或者,几十年之后,我还能用到Firefox吗?</p><p>声明:</p><blockquote><p>本文没有任何贬低Firefox的意思。Firefox是个很优秀的浏览器,特别是自带的<code>Web开发</code>控制台特别强大。老灯长期使用 Linux + Firefox, 虽然Chromium也是有在使用的,截止目前,Firefox依旧是老灯在Linux下的主力浏览器。</p></blockquote> Wed, 20 May 2020 15:56:33 GMT ttyS3 troubleshootfirefoxbug https://ttys3.dev/blog/gnome-bluetooth-how-to-auto-reconnect GNOME Bluetooth 自动重连问题的解决 https://ttys3.dev/blog/gnome-bluetooth-how-to-auto-reconnect <p>系统版本: Fedora 32</p><p>GNOME版本: 3.36.2</p><h2 id="问题分析"><a href="#问题分析" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>问题分析</h2><p>很久之前买了个天猫精灵X1蓝牙音响,周末偶尔也会用台式机连一下看看电影啥的。</p><p>但是GNOME bluetooth 有个问题就是,第一次可以配对成功并连接上,下次开机重启后它就不会自动连接了。并且就算你想手动点击连接,也非常大的概率无法成功,大部分情况下,你尝试点击那个连接的开关它会马上切换到未连接的状态,如图示:</p><div><img alt="gnome-bluetooth-can-not-reconnect" src="https://ttys3.dev/static/assets/gnome-bluetooth-can-not-reconnect-2020-05-20-19-46-JWXLOKST.gif" width="948" height="574"/></div><p>当然,如果有耐心的话,多点击几次,还是有可能成功的。比如像我这样点了14下才成功:</p><div><img alt="gnome-bluetooth-device-busy-2020-05-20-20-11.gif" src="https://ttys3.dev/static/assets/gnome-bluetooth-device-busy-2020-05-20-20-11-666N3H2I.gif" width="1701" height="579"/></div><p>当然,要不是我<code>sudo journalctl -f -u bluetooth</code>打开了日志,我可能会认为这个按钮是“自动反弹”的而放弃继续点击。</p><p>现在我们知道了,只要耐心的点,总有一次会成功的。</p><p>我们来看看日志:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> journalctl <span class="token variable parameter">-f</span> <span class="token variable parameter">-u</span> bluetooth </span><span class="code-line"><span class="token punctuation">[</span>sudo<span class="token punctuation">]</span> password <span class="token keyword">for</span> ttys3: </span><span class="code-line">-- Logs begin at Thu <span class="token number">2020</span>-01-09 03:44:38 CST. -- </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:07:43 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2771</span><span class="token punctuation">]</span>: Exit </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:07:43 8700k.localhost systemd<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>: bluetooth.service: Succeeded. </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:07:43 8700k.localhost systemd<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>: Stopped Bluetooth service. </span><span class="code-line">-- Reboot -- </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:08:17 8700k.localhost systemd<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>: Starting Bluetooth service<span class="token punctuation">..</span>. </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:08:17 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: Bluetooth daemon <span class="token number">5.54</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:08:17 8700k.localhost systemd<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>: Started Bluetooth service. </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:08:17 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: Starting SDP server </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:08:17 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: Bluetooth management interface <span class="token number">1.15</span> initialized </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:08:34 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: Endpoint registered: <span class="token variable assign-left">sender</span><span class="token operator">=</span>:1.76 <span class="token variable assign-left">path</span><span class="token operator">=</span>/MediaEndpoint/A2DPSink/sbc </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:08:34 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: Endpoint registered: <span class="token variable assign-left">sender</span><span class="token operator">=</span>:1.76 <span class="token variable assign-left">path</span><span class="token operator">=</span>/MediaEndpoint/A2DPSource/sbc </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:12 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:14 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:16 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:17 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:18 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:19 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:20 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:21 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:22 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:24 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:25 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:26 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:27 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:28 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: connect error: Device or resource busy <span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span> </span><span class="code-line">May <span class="token number">20</span> <span class="token number">20</span>:11:32 8700k.localhost bluetoothd<span class="token punctuation">[</span><span class="token number">2768</span><span class="token punctuation">]</span>: /org/bluez/hci0/dev_18_BC_5A_A5_54_DB/sep1/fd0: fd<span class="token punctuation">(</span><span class="token number">46</span><span class="token punctuation">)</span> ready </span></code></pre></div><p>可见没法连接成功的情况都是<code>connect error: Device or resource busy (16)</code>, 而连接成功的情况则是<code>/org/bluez/hci0/dev_18_BC_5A_A5_54_DB/sep1/fd3: fd(43) ready</code> 这种。</p><p>好了,现在我们总结一下问题:</p><ol><li>首次配对是可以连接成功并正常使用的</li><li>系统重启后蓝牙音响没有自动连接。手动点击要点十多下才可能成功。</li><li>根据条件1,我们尝试重启后删除蓝牙音响并重新配对也是OK的。</li></ol><p>无论是一次又一次的删除和添加配对,还是每次开机点十几下连接个蓝牙音响,都挺麻烦的,有没有办法让它开机自动重连蓝牙音响呢?</p><p>办法当然是有的。</p><h2 id="解决开机自动重连问题"><a href="#解决开机自动重连问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>解决开机自动重连问题</h2><p><code>bluez</code> 这个Bluetooth utilities包里,包含了<code>bluetoothctl</code>这个实用工具,我们可以用它来完成自动连接。</p><p>新建一文件 <code>/opt/scripts/bluetooth-auto-connect.sh</code> (<code>/opt/scripts</code>目录不存在,自己新建一个即可), 内容如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token important shebang">#!/bin/sh</span> </span><span class="code-line"> </span><span class="code-line"><span class="token variable assign-left">DEVICE</span><span class="token operator">=</span><span class="token string">&quot;18:BC:5A:A5:54:DB&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token variable assign-left">BLCTL</span><span class="token operator">=</span>/usr/bin/bluetoothctl </span><span class="code-line"> </span><span class="code-line"><span class="token variable">$BLCTL</span> power on </span><span class="code-line"><span class="token variable">$BLCTL</span> agent on </span><span class="code-line"><span class="token variable">$BLCTL</span> default-agent </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">if</span> <span class="token variable">$BLCTL</span> info <span class="token variable">$DEVICE</span><span class="token punctuation">;</span> <span class="token keyword">then</span> </span><span class="code-line"><span class="token variable">$BLCTL</span> trust <span class="token variable">$DEVICE</span> <span class="token operator">&amp;&amp;</span> <span class="token variable">$BLCTL</span> connect <span class="token variable">$DEVICE</span> </span><span class="code-line"><span class="token keyword">fi</span> </span></code></pre></div><p><code>18:BC:5A:A5:54:DB</code> 是蓝牙音响的MAC地址(注意这个设备是已经成功配对过的)。</p><p>注意这里我们执行了<code>trust</code>命令,这是必要的。要不然无法连接成功。</p><p>MAC地址可以通过Gnome图片界面查看到,也可以用命令行:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ bluetoothctl devices </span><span class="code-line">Device 03:D1:64:4D:26:A1 03-D1-64-4D-26-A1 </span><span class="code-line">Device <span class="token number">70</span>:0E:47:34:2A:F1 <span class="token number">70</span>-0E-47-34-2A-F1 </span><span class="code-line">Device <span class="token number">62</span>:BB:F2:90:DC:7A <span class="token number">62</span>-BB-F2-90-DC-7A </span><span class="code-line">Device 1E:0F:C3:CF:6D:AF 1E-0F-C3-CF-6D-AF </span><span class="code-line">Device <span class="token number">18</span>:BC:5A:A5:54:DB X1<span class="token punctuation">(</span>F0:6B<span class="token punctuation">)</span> </span></code></pre></div><p><code>18:BC:5A:A5:54:DB</code> 就是天猫精灵X1的MAC了。</p><p>然后我们在Gnome的自动启动目录<code>~/.config/autostart</code>下新建一desktop文件<code>bluetooth-auto-connect.desktop</code>, 内容如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Desktop Entry</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token attr-name key">Name</span><span class="token punctuation">=</span><span class="token attr-value value">bluetooth-auto-connect</span> </span><span class="code-line"><span class="token attr-name key">GenericName</span><span class="token punctuation">=</span><span class="token attr-value value">bluetooth-auto-connect</span> </span><span class="code-line"><span class="token attr-name key">Exec</span><span class="token punctuation">=</span><span class="token attr-value value">/opt/scripts/bluetooth-auto-connect.sh</span> </span><span class="code-line"><span class="token attr-name key">Terminal</span><span class="token punctuation">=</span><span class="token attr-value value">false</span> </span><span class="code-line"><span class="token attr-name key">Icon</span><span class="token punctuation">=</span><span class="token attr-value value">bash</span> </span><span class="code-line"><span class="token attr-name key">Categories</span><span class="token punctuation">=</span><span class="token attr-value value">Audio</span> </span><span class="code-line"><span class="token attr-name key">Type</span><span class="token punctuation">=</span><span class="token attr-value value">Application</span> </span><span class="code-line"><span class="token attr-name key">StartupNotify</span><span class="token punctuation">=</span><span class="token attr-value value">false</span> </span><span class="code-line"><span class="token attr-name key">X-GNOME-Autostart-enabled</span><span class="token punctuation">=</span><span class="token attr-value value">true</span> </span></code></pre></div><p>这样就能在用户登录后自动执行蓝牙连接了。</p><p>如果开启了selinux, 注意设置一下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> chcon <span class="token variable parameter">-t</span> bin_t /opt/scripts/bluetooth-auto-connect.sh </span></code></pre></div><p>连接成功后可以通过以下命令查看蓝牙设备信息:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ bluetoothctl info <span class="token number">18</span>:BC:5A:A5:54:DB </span><span class="code-line">Device <span class="token number">18</span>:BC:5A:A5:54:DB <span class="token punctuation">(</span>public<span class="token punctuation">)</span> </span><span class="code-line"> Name: X1<span class="token punctuation">(</span>F0:6B<span class="token punctuation">)</span> </span><span class="code-line"> Alias: X1<span class="token punctuation">(</span>F0:6B<span class="token punctuation">)</span> </span><span class="code-line"> Class: 0x002c0414 </span><span class="code-line"> Icon: audio-card </span><span class="code-line"> Paired: <span class="token function">yes</span> </span><span class="code-line"> Trusted: <span class="token function">yes</span> </span><span class="code-line"> Blocked: no </span><span class="code-line"> Connected: <span class="token function">yes</span> </span><span class="code-line"> LegacyPairing: no </span><span class="code-line"> UUID: Audio Sink <span class="token punctuation">(</span>0000110b-0000-1000-8000-00805f9b34fb<span class="token punctuation">)</span> </span><span class="code-line"> UUID: A/V Remote Control Target <span class="token punctuation">(</span>0000110c-0000-1000-8000-00805f9b34fb<span class="token punctuation">)</span> </span><span class="code-line"> UUID: A/V Remote Control <span class="token punctuation">(</span>0000110e-0000-1000-8000-00805f9b34fb<span class="token punctuation">)</span> </span><span class="code-line"> UUID: PnP Information <span class="token punctuation">(</span>00001200-0000-1000-8000-00805f9b34fb<span class="token punctuation">)</span> </span><span class="code-line"> UUID: Generic Access Profile <span class="token punctuation">(</span>00001800-0000-1000-8000-00805f9b34fb<span class="token punctuation">)</span> </span><span class="code-line"> UUID: Generic Attribute Profile <span class="token punctuation">(</span>00001801-0000-1000-8000-00805f9b34fb<span class="token punctuation">)</span> </span><span class="code-line"> Modalias: bluetooth:v000Fp1200d1436 </span></code></pre></div><h2 id="开机连接成功后自动切换"><a href="#开机连接成功后自动切换" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>开机连接成功后自动切换</h2><p>如果你希望PulseAudio自动连接到新发现的输出设备, 可以修改<code>/etc/pulse/default.pa</code>, 增加:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment"># bluetooth: automatically switch to newly-connected devices</span> </span><span class="code-line"><span class="token comment"># https://wiki.archlinux.org/index.php/Bluetooth_headset#Setting_up_auto_connection</span> </span><span class="code-line">load-module module-switch-on-connect </span></code></pre></div><p>或者添加到pulse用户配置文件<code>~/.config/pulse/default.pa</code>也OK。 文件不存在则新建一个或从<code>/etc/pulse/default.pa</code> copy一个过来。</p><p>什么是PulseAudio?</p><blockquote><p>PulseAudio 是在 GNOME 或 KDE 等桌面环境中广泛使用的音频服务。它在内核音频组件(比如ALSA 和 OSS)和应用程序之间充当代理的角色。 PulseAudio经常和ALSA协同使用。</p></blockquote><p>所以PulseAudio它是一个middleware, 应用程序想要输出声音,可以找Pulse,然后Pulse再找底层的组件比如ALSA。</p><p>当然,PulseAudio并不是必须的。一些应用程序,比如DeaDBeeF和SMPlayer 允许用户配置声音输出。 比如DeaDBeeF就有三个选择,ALSA, OSS或 Pulse。当选择为ALSA时,DeaDBeeF还会允许你选择用哪个设备输出声音。</p><div><img alt="" src="https://ttys3.dev/static/assets/deadbeef-sound-use-pulse-2020-05-20-20-44-33-MB5UK3A2.png" width="1318" height="374"/></div><div><img alt="" src="https://ttys3.dev/static/assets/deadbeef-audio-config-2020-05-20-20-44-02-U5LFZGHY.png" width="1362" height="670"/></div><p>一般来说,我们让应用程序都使用<code>PulseAudio</code>, 然后让<code>PulseAudio</code>统一管理会比较好。 比如我们将输出设备从<strong>Audioengine D1</strong>切换到<strong>天猫精灵X1</strong>时, 所有应用程序就统一切换了,假如是单独用<code>ALSA</code>设置的,那还得单个去改,挺麻烦的。</p><h2 id="参数文档"><a href="#参数文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参数文档</h2><p><a href="https://wiki.archlinux.org/index.php/PulseAudio">https://wiki.archlinux.org/index.php/PulseAudio</a></p><p><a href="https://wiki.debian.org/BluetoothUser#Can.27t_reconnect_after_sleep">https://wiki.debian.org/BluetoothUser#Can.27t_reconnect_after_sleep</a></p><p><a href="https://wiki.archlinux.org/index.php/Bluetooth_headset#Configuration_via_CLI">https://wiki.archlinux.org/index.php/Bluetooth_headset#Configuration_via_CLI</a></p> Wed, 20 May 2020 11:41:20 GMT ttyS3 GNOMEbluetoothfedora https://ttys3.dev/blog/git-how-to-commit-only-parts-of-a-file Git tips -- 同一个文件修改了多处如何分作多个提交 https://ttys3.dev/blog/git-how-to-commit-only-parts-of-a-file <h2 id="需求"><a href="#需求" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>需求</h2><p>经常会有这么一种情况,一个文件修改了很多次代码,才发现 -- 咦?忘记commit了。 而且往往这些修改可能它们本来应该属于不同的提交。</p><p>怎么办?总不可能将就一下,直接把一些乱七八糟的修改放在一个commit里吧?</p><p>这个时候git add的<code>-p, --patch</code>参数就派上大用场了。</p><h2 id="介绍"><a href="#介绍" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>介绍</h2><blockquote><p><code>-p, --patch</code> Interactively choose hunks of patch between the index and the work tree and add them to the index. This gives the user a chance to review the difference before adding modified contents to the index. This effectively runs add --interactive, but bypasses the initial command menu and directly jumps to the patch subcommand. See “Interactive mode” for details.</p></blockquote><p><code>hunks</code> 是一个GNU diff用语, 见 <a href="http://www.gnu.org/software/diffutils/manual/html_node/Hunks.html">http://www.gnu.org/software/diffutils/manual/html_node/Hunks.html</a></p><blockquote><p>When comparing two files, <code>diff</code> finds sequences of lines common to both files, interspersed with groups of differing lines called <strong>hunks</strong></p></blockquote><p>因此,简单来说,<code>hunks</code> 就是指两个文件对比时的一组一组的差异行。</p><p>当我们进行git add时,默认是把整个文件添加进去了。当按<code>hunks</code>选取时,我们便可以自由地选取任意的hunks组成一个commit.</p><h2 id="实战"><a href="#实战" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>实战</h2><p>举个最简单的例子,假设 hello.c 原内容如下:</p><div class="relative"><pre><code class="code-highlight language-c"><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;stdio.h&gt;</span></span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">typedef</span> <span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span>greet_func<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">void</span> <span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> greet_func greet <span class="token operator">=</span> sayHello<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">greet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">void</span> <span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">&quot;Hello from ttys3.net\n&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>为了完成后续的操作,你需要新建一git仓库,然后添加如上文件,并完成初次提交。</p><p>然后,我们将文件修改,假设它变成了如下内容(此处这些改动并无实际意义,只是为了方便演示做的修改):</p><p><code>hello.c</code>第 <code>1,3,5,7,9</code> 行都被修改了,如果我想把<code>1, 9</code>(都标了<code>//1</code>)组成一个commit,把<code>3,5,7</code> (都标了<code>//2</code>) 组成另一个commit, 要如何操作?</p><div class="relative"><pre><code class="code-highlight language-c"><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token keyword directive">include</span> <span class="token string">&lt;stdio.h&gt;</span> <span class="token comment">//1</span></span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">typedef</span> <span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span>greet_func<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//2</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">void</span> <span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//2</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//2</span> </span><span class="code-line"> greet_func greet <span class="token operator">=</span> sayHello<span class="token punctuation">;</span> </span><span class="code-line"> <span class="token function">greet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//1</span> </span><span class="code-line"> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">void</span> <span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">&quot;Hello from ttys3.net\n&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>当前状态:已修改,未stage, 用<code>git diff</code>可以看到如下结果:</p><div class="relative"><pre><code class="code-highlight language-diff"><span class="code-line">diff --git a/hello.c b/hello.c </span><span class="code-line">index 0968d02..bf5082a 100644 </span><span class="code-line deleted"><span class="token coord">--- a/hello.c</span> </span><span class="code-line inserted"><span class="token coord">+++ b/hello.c</span> </span><span class="code-line"><span class="token coord">@@ -1,12 +1,12 @@</span> </span><span class="code-line deleted"><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line">#include &lt;stdio.h&gt; </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line">#include &lt;stdio.h&gt; //1 </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line">typedef void (*greet_func)(); </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line">typedef void (*greet_func)(); //2 </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line">void sayHello(); </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line">void sayHello(); //2 </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line">int main() { </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line">int main() { //2 </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> greet_func greet = sayHello; </span></span></span><span class="code-line deleted"><span class="token unchanged"><span class="token line"></span></span><span class="token deleted deleted-sign"><span class="token deleted prefix">-</span><span class="token line"> greet(); </span></span></span><span class="code-line inserted"><span class="token deleted deleted-sign"><span class="token line"></span></span><span class="token inserted inserted-sign"><span class="token inserted prefix">+</span><span class="token line"> greet(); //1 </span></span></span><span class="code-line"><span class="token inserted inserted-sign"><span class="token line"></span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> return 0; </span></span></span><span class="code-line"><span class="token unchanged"><span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line">} </span></span></span></code></pre></div><p>我们执行<code>git add -p hello.c</code>:</p><div><img alt="" src="https://ttys3.dev/static/assets/git-add-with-patch-param-2020-05-17-00-20-21-ZKTXLAKC.png" width="728" height="826"/></div><p>由于我们这个修改实在是太小了,直接被Git识别成一个<code>hunk</code>了,怎么办?</p><p>这个<code>(1/1) Stage this hunk [y,n,q,a,d,s,e,?]? </code>提示是什么意思?</p><p>执行<code>git add --help</code>然后跳到<code>INTERACTIVE MODE</code> 下的 <code>patch</code>部分,有详细的解释</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">patch </span><span class="code-line"> This lets you choose one path out of a status like selection. After choosing the path, it presents the <span class="token function">diff</span> between the index and the working tree <span class="token function">file</span> and asks you <span class="token keyword">if</span> you want to stage the change of each hunk. You can </span><span class="code-line"> <span class="token keyword">select</span> one of the following options and <span class="token builtin class-name">type</span> return: </span><span class="code-line"> </span><span class="code-line"> y - stage this hunk </span><span class="code-line"> n - <span class="token keyword">do</span> not stage this hunk </span><span class="code-line"> q - quit<span class="token punctuation">;</span> <span class="token keyword">do</span> not stage this hunk or any of the remaining ones </span><span class="code-line"> a - stage this hunk and all later hunks <span class="token keyword">in</span> the <span class="token function">file</span> </span><span class="code-line"> d - <span class="token keyword">do</span> not stage this hunk or any of the later hunks <span class="token keyword">in</span> the <span class="token function">file</span> </span><span class="code-line"> g - <span class="token keyword">select</span> a hunk to go to </span><span class="code-line"> / - search <span class="token keyword">for</span> a hunk matching the given regex </span><span class="code-line"> j - leave this hunk undecided, see next undecided hunk </span><span class="code-line"> J - leave this hunk undecided, see next hunk </span><span class="code-line"> k - leave this hunk undecided, see previous undecided hunk </span><span class="code-line"> K - leave this hunk undecided, see previous hunk </span><span class="code-line"> s - <span class="token function">split</span> the current hunk into smaller hunks </span><span class="code-line"> e - manually edit the current hunk </span><span class="code-line"> ? - print <span class="token builtin class-name">help</span> </span><span class="code-line"> </span><span class="code-line"> After deciding the fate <span class="token keyword">for</span> all hunks, <span class="token keyword">if</span> there is any hunk that was chosen, the index is updated with the selected hunks. </span><span class="code-line"> </span><span class="code-line"> You can omit having to <span class="token builtin class-name">type</span> <span class="token builtin class-name">return</span> here, by setting the configuration variable interactive.singleKey to true. </span></code></pre></div><p>默认是按下上述键后还需要按下回车确认的,如果想要直接单键确认,可以修改配置 <code>interactive.singleKey = true</code></p><p>老灯简单解释下:</p><p>(所有的操作都是针对hunk的)</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"> y - 取了 </span><span class="code-line"> n - 不取 </span><span class="code-line"> q - 我不干了,啥也别add,退出吧 </span><span class="code-line"> a - 取了这个和此文件后续所有的 </span><span class="code-line"> d - 这个不取了,此文件后续所有的我也不取了 </span><span class="code-line"> g - 搜索以跳到某个hunk </span><span class="code-line"> / - 以正则搜索某个hunk </span><span class="code-line"> j - 这个未决, 并跳到下一个未决hunk </span><span class="code-line"> J - 这个未决, 并跳到下一个hunk </span><span class="code-line"> k - 这个未决, 并跳到上一个未决hunk </span><span class="code-line"> K - 这个未决, 并跳到上一个hunk </span><span class="code-line"> s - 这个hunk太大了,拆分成更小的hunks吧 </span><span class="code-line"> e - 手动编辑当前hunk </span><span class="code-line"> ? - 显示当前帮助信息<span class="token punctuation">(</span>当你不记得这些缩写是什么意思时相当有用<span class="token punctuation">)</span> </span></code></pre></div><p>好了,回到我们之前的操作,很明显,我们是要按<code>s</code>将这个hunk继续拆分。</p><p>OK,这次被拆分成5个hunks了, 我们先完成第一个commit:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 按s再回车确认(默认配置都要回车的,后续省略不写了), 拆成更小的hunks</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> Stage this hunk <span class="token punctuation">[</span>y,n,q,a,d,s,e,?<span class="token punctuation">]</span>? s </span><span class="code-line">Split into <span class="token number">5</span> hunks. </span><span class="code-line">@@ -1,2 +1,2 @@ </span><span class="code-line">-<span class="token comment">#include &lt;stdio.h&gt;</span> </span><span class="code-line">+<span class="token comment">#include &lt;stdio.h&gt; //1</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 这个是我们要取的,按y</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">1</span>/5<span class="token punctuation">)</span> Stage this hunk <span class="token punctuation">[</span>y,n,q,a,d,j,J,g,/,e,?<span class="token punctuation">]</span>? y </span><span class="code-line">@@ -2,3 +2,3 @@ </span><span class="code-line"> </span><span class="code-line"><span class="token parameter variable">-typedef</span> void <span class="token punctuation">(</span>*greet_func<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line">+typedef void <span class="token punctuation">(</span>*greet_func<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> //2 </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 这个hunk不是我们第一个commit里需要的,按n</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">2</span>/5<span class="token punctuation">)</span> Stage this hunk <span class="token punctuation">[</span>y,n,q,a,d,K,j,J,g,/,e,?<span class="token punctuation">]</span>? n </span><span class="code-line">@@ -4,3 +4,3 @@ </span><span class="code-line"> </span><span class="code-line"><span class="token parameter variable">-void</span> sayHello<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line">+void sayHello<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> //2 </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 这个hunk不是我们第一个commit里需要的,按n</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">3</span>/5<span class="token punctuation">)</span> Stage this hunk <span class="token punctuation">[</span>y,n,q,a,d,K,j,J,g,/,e,?<span class="token punctuation">]</span>? n </span><span class="code-line">@@ -6,3 +6,3 @@ </span><span class="code-line"> </span><span class="code-line"><span class="token parameter variable">-int</span> <span class="token function function-name">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line">+int <span class="token function function-name">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> //2 </span><span class="code-line"> greet_func greet <span class="token operator">=</span> sayHello<span class="token punctuation">;</span> </span><span class="code-line"><span class="token comment"># 这个hunk不是我们第一个commit里需要的,按n</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">4</span>/5<span class="token punctuation">)</span> Stage this hunk <span class="token punctuation">[</span>y,n,q,a,d,K,j,J,g,/,e,?<span class="token punctuation">]</span>? n </span><span class="code-line">@@ -8,5 +8,5 @@ </span><span class="code-line"> greet_func greet <span class="token operator">=</span> sayHello<span class="token punctuation">;</span> </span><span class="code-line">- greet<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line">+ greet<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> //1 </span><span class="code-line"> <span class="token builtin class-name">return</span> <span class="token number">0</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 这个是我们要取的,按y</span> </span><span class="code-line"><span class="token punctuation">(</span><span class="token number">5</span>/5<span class="token punctuation">)</span> Stage this hunk <span class="token punctuation">[</span>y,n,q,a,d,K,g,/,e,?<span class="token punctuation">]</span>? y </span></code></pre></div><p>我们<code>git status</code>看看,现在是这样的:</p><div><img alt="" src="https://ttys3.dev/static/assets/git-interactive-staging-step-1-2020-05-17-00-37-48-EP6LSMU6.png" width="1174" height="370"/></div><p>再<code>git diff</code>看看,发现剩下的都是我们第二个commit要取的了:</p><div><img alt="" src="https://ttys3.dev/static/assets/git-diff-show-left-hunks-2020-05-17-00-38-53-75546HCI.png" width="622" height="658"/></div><p>好了,现在我们先<code>git commit</code>把刚才取的这些hunks先commit:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">git</span> ci <span class="token parameter variable">-m</span> <span class="token string">&#x27;commit 1&#x27;</span> </span><span class="code-line"><span class="token punctuation">[</span>master 3f9a5ed<span class="token punctuation">]</span> commit <span class="token number">1</span> </span><span class="code-line"> <span class="token number">1</span> <span class="token function">file</span> changed, <span class="token number">2</span> insertions<span class="token punctuation">(</span>+<span class="token punctuation">)</span>, <span class="token number">2</span> deletions<span class="token punctuation">(</span>-<span class="token punctuation">)</span> </span></code></pre></div><p>由于剩下的是另一个提交的,因此就可以直接<code>git add hello.c</code>再commit了:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">git</span> <span class="token function">add</span> hello.c </span><span class="code-line">❯ <span class="token function">git</span> ci <span class="token parameter variable">-m</span> <span class="token string">&#x27;commit 2&#x27;</span> </span><span class="code-line"><span class="token punctuation">[</span>master ae734d3<span class="token punctuation">]</span> commit <span class="token number">2</span> </span><span class="code-line"> <span class="token number">1</span> <span class="token function">file</span> changed, <span class="token number">3</span> insertions<span class="token punctuation">(</span>+<span class="token punctuation">)</span>, <span class="token number">3</span> deletions<span class="token punctuation">(</span>-<span class="token punctuation">)</span> </span></code></pre></div><p>好了,我们验证一下。</p><p>先看一下第一个提交的改动 <code>git show @^</code></p><div><img alt="" src="https://ttys3.dev/static/assets/git-show-diff-commit-12020-05-17-00-44-41-V7IAFROP.png" width="590" height="760"/></div><p>再看一下第二个提交的改动<code>git show @</code></p><div><img alt="" src="https://ttys3.dev/static/assets/git-show-diff-commit-2-2020-05-17-00-45-22-DAX6TDYW.png" width="578" height="708"/></div><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><code>man 1 git-add</code> or <code>git add --help</code></p><p><a href="https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging">https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging</a></p> Sat, 16 May 2020 15:43:48 GMT ttyS3 githunksinteractive-staging https://ttys3.dev/blog/git-fixup-amend-for-any-older-commits-quickly 超实用的 Git fixup 神技 -- 一键修复任意commit https://ttys3.dev/blog/git-fixup-amend-for-any-older-commits-quickly <h2 id="热身运动"><a href="#热身运动" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>热身运动</h2><p>如果你没有设置一些惯用alias, 比如<code>ci</code>之类的,自行将<code>ci</code>替换成 <code>commit</code>。</p><p>像命令中用到的<code>lg1</code>别名,请直接跳到文章最后取配置。</p><p>为了方便理解,老灯会创建一个简单的Git仓库,用如下命令可完成:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 新建一个演练仓库</span> </span><span class="code-line"><span class="token function">mkdir</span> gittest </span><span class="code-line"><span class="token builtin class-name">cd</span> gittest </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 随便添加一个文件</span> </span><span class="code-line"><span class="token function">touch</span> hello.txt </span><span class="code-line"><span class="token function">git</span> <span class="token function">add</span> hello.txt </span><span class="code-line"><span class="token function">git</span> ci <span class="token parameter variable">-m</span> <span class="token string">&#x27;add hello.txt&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 再随便添加一个文件</span> </span><span class="code-line"><span class="token function">touch</span> world.txt </span><span class="code-line"><span class="token function">git</span> <span class="token function">add</span> world.txt </span><span class="code-line"><span class="token function">git</span> ci <span class="token parameter variable">-m</span> <span class="token string">&#x27;add world.txt&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 现在的提交是这样的</span> </span><span class="code-line">❯ <span class="token function">git</span> lg1 </span><span class="code-line">* 95863b6 - <span class="token punctuation">(</span><span class="token number">62</span> seconds ago<span class="token punctuation">)</span> <span class="token function">add</span> world.txt - 荒野無燈 <span class="token punctuation">(</span>HEAD -<span class="token operator">&gt;</span> master<span class="token punctuation">)</span> </span><span class="code-line">* a956ae3 - <span class="token punctuation">(</span><span class="token number">72</span> seconds ago<span class="token punctuation">)</span> <span class="token function">add</span> hello.txt - 荒野無燈 </span></code></pre></div><h2 id="amend神技"><a href="#amend神技" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>amend神技</h2><p>我们先熟悉下<code>--amend</code>的用法,这个也是老灯日常开发中用得特别多的一个参数。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 现在我们要修改最后这个提交,比如突然想起来, world.txt 文件里我们应该写一个 &quot;test&quot;</span> </span><span class="code-line"> <span class="token builtin class-name">echo</span> <span class="token builtin class-name">test</span> <span class="token operator">&gt;</span> ./world.txt </span><span class="code-line"><span class="token comment"># 添加进stage</span> </span><span class="code-line"><span class="token function">git</span> <span class="token function">add</span> <span class="token parameter variable">-u</span> </span><span class="code-line"><span class="token comment"># 提交</span> </span><span class="code-line"><span class="token function">git</span> ci <span class="token parameter variable">--amend</span> </span><span class="code-line"><span class="token comment"># 然后我们再看看, 发现最后那个提交的commit id变了, 并且在这个提交里world.txt文件默认有内容 &quot;test&quot;</span> </span><span class="code-line"><span class="token comment"># 可以用git show查看, 没错,这就是`--amend`的神奇效果</span> </span><span class="code-line">❯ <span class="token function">git</span> lg1 </span><span class="code-line">* c17a18a - <span class="token punctuation">(</span><span class="token number">4</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> world.txt - 荒野無燈 <span class="token punctuation">(</span>HEAD -<span class="token operator">&gt;</span> master<span class="token punctuation">)</span> </span><span class="code-line">* a956ae3 - <span class="token punctuation">(</span><span class="token number">4</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> hello.txt - 荒野無燈 </span></code></pre></div><p>但是,人是很容易犯错误的, 特别是有时候,你已经提交过两次了,才发现上上个提交还有东西没有加上。 此时你又不想再提交一个新的commit, 因为这样整个commit就不整洁了,并且,提交记录看起来会很散乱。</p><p>为了接下来的演示,我们要在之前的两个提交的基础上再加一个:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">touch</span> README.md </span><span class="code-line"><span class="token function">git</span> <span class="token function">add</span> README.md </span><span class="code-line"><span class="token function">git</span> ci <span class="token parameter variable">-m</span> <span class="token string">&#x27;add README.md&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 现在的仓库看起来像这样了</span> </span><span class="code-line">❯ <span class="token function">git</span> lg1 </span><span class="code-line">* 76091ea - <span class="token punctuation">(</span><span class="token number">42</span> seconds ago<span class="token punctuation">)</span> <span class="token function">add</span> README.md - 荒野無燈 <span class="token punctuation">(</span>HEAD -<span class="token operator">&gt;</span> master<span class="token punctuation">)</span> </span><span class="code-line">* c17a18a - <span class="token punctuation">(</span><span class="token number">13</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> world.txt - 荒野無燈 </span><span class="code-line">* a956ae3 - <span class="token punctuation">(</span><span class="token number">13</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> hello.txt - 荒野無燈 </span></code></pre></div><h2 id="commit拆分大法的歪用"><a href="#commit拆分大法的歪用" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>commit拆分大法的歪用</h2><p>没错,买一送一啦。取fixup大法,还顺便送了个Git commit拆分大法。</p><p>在没有看到这个tips之前,老灯先说一下之前一直在用的&quot;超级麻烦做法&quot;(实际上是对&quot;Git commit拆分大法&quot;的应用):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># &lt;commit&gt;是需要修改的那个提交, 然后标记&lt;commit&gt;为 edit (改写为`e`即可)</span> </span><span class="code-line"><span class="token function">git</span> rebase <span class="token parameter variable">-i</span> <span class="token operator">&lt;</span>commit<span class="token operator">&gt;</span>^ </span><span class="code-line"><span class="token function">git</span> reset HEAD^ </span><span class="code-line"><span class="token comment"># 进行修改操作(或者commit拆分操作)</span> </span><span class="code-line"><span class="token comment"># 添加需要提交的文件到index</span> </span><span class="code-line"><span class="token function">git</span> <span class="token function">add</span> 需要添加的文件 </span><span class="code-line"><span class="token comment"># 提交修改</span> </span><span class="code-line"><span class="token function">git</span> ci <span class="token parameter variable">-m</span> <span class="token string">&#x27;blah blah&#x27;</span> </span><span class="code-line"><span class="token comment"># ... 继续添加第二个commit,如果有需要(当然,在拆分时肯定会有第2个commit了)</span> </span><span class="code-line"><span class="token comment"># 完成commit之后,继续rebase</span> </span><span class="code-line"><span class="token function">git</span> rebase <span class="token parameter variable">--continue</span> </span></code></pre></div><p>具体到我们这个demo仓库,则是:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 我们要修改的是 c17a18a</span> </span><span class="code-line"><span class="token function">git</span> rebase <span class="token parameter variable">-i</span> c17a18a^ </span></code></pre></div><p>然后Git会调用默认文件编辑器,弹出以下类似的内容:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">pick c17a18a <span class="token function">add</span> world.txt </span><span class="code-line">pick 76091ea <span class="token function">add</span> README.md </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Rebase a956ae3..76091ea onto a956ae3 (2 commands)</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># Commands:</span> </span><span class="code-line"><span class="token comment"># p, pick &lt;commit&gt; = use commit</span> </span><span class="code-line"><span class="token comment"># r, reword &lt;commit&gt; = use commit, but edit the commit message</span> </span><span class="code-line"><span class="token comment"># e, edit &lt;commit&gt; = use commit, but stop for amending</span> </span><span class="code-line"><span class="token comment"># s, squash &lt;commit&gt; = use commit, but meld into previous commit</span> </span><span class="code-line"><span class="token comment"># f, fixup &lt;commit&gt; = like &quot;squash&quot;, but discard this commit&#x27;s log message</span> </span><span class="code-line"><span class="token comment"># x, exec &lt;command&gt; = run command (the rest of the line) using shell</span> </span><span class="code-line"><span class="token comment"># b, break = stop here (continue rebase later with &#x27;git rebase --continue&#x27;)</span> </span><span class="code-line"><span class="token comment"># d, drop &lt;commit&gt; = remove commit</span> </span><span class="code-line"><span class="token comment"># l, label &lt;label&gt; = label current HEAD with a name</span> </span><span class="code-line"><span class="token comment"># t, reset &lt;label&gt; = reset HEAD to a label</span> </span><span class="code-line"><span class="token comment"># m, merge [-C &lt;commit&gt; | -c &lt;commit&gt;] &lt;label&gt; [# &lt;oneline&gt;]</span> </span><span class="code-line"><span class="token comment"># . create a merge commit using the original merge commit&#x27;s</span> </span><span class="code-line"><span class="token comment"># . message (or the oneline, if no original merge commit was</span> </span><span class="code-line"><span class="token comment"># . specified). Use -c &lt;commit&gt; to reword the commit message.</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># These lines can be re-ordered; they are executed from top to bottom.</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># If you remove a line here THAT COMMIT WILL BE LOST.</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># However, if you remove everything, the rebase will be aborted.</span> </span><span class="code-line"><span class="token comment">#</span> </span></code></pre></div><p>我们把<code>c17a18a</code>标记为 edit (改写为<code>e</code>即可), 然后保存:</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line">e c17a18a add world<span class="token punctuation">.</span><span class="token property-access">txt</span> </span><span class="code-line">pick 76091ea add <span class="token constant">README</span><span class="token punctuation">.</span><span class="token property-access">md</span> </span></code></pre></div><p>然后执行<code>git reset HEAD^</code> 就可以开始修改了, 比如,随便改点东西:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">echo</span> <span class="token string">&#x27;test older commit fixup&#x27;</span> <span class="token operator">&gt;</span> world.txt </span></code></pre></div><p>提交:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">git</span> <span class="token function">add</span> world.txt </span><span class="code-line"><span class="token function">git</span> ci <span class="token parameter variable">-m</span> <span class="token string">&#x27;udpate world.txt&#x27;</span> </span><span class="code-line">❯ <span class="token function">git</span> rebase <span class="token parameter variable">--continue</span> </span><span class="code-line">Successfully rebased and updated refs/heads/master. </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 现在我们再看看commit history</span> </span><span class="code-line">❯ <span class="token function">git</span> lg1 </span><span class="code-line">* 3562e20 - <span class="token punctuation">(</span><span class="token number">10</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> README.md - 荒野無燈 <span class="token punctuation">(</span>HEAD -<span class="token operator">&gt;</span> master<span class="token punctuation">)</span> </span><span class="code-line">* ade3438 - <span class="token punctuation">(</span><span class="token number">57</span> seconds ago<span class="token punctuation">)</span> update world.txt - 荒野無燈 </span><span class="code-line">* a956ae3 - <span class="token punctuation">(</span><span class="token number">23</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> hello.txt - 荒野無燈 </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># git show ade3438 可以看到如下内容</span> </span><span class="code-line"><span class="token function">diff</span> <span class="token parameter variable">--git</span> a/world.txt b/world.txt </span><span class="code-line">new <span class="token function">file</span> mode <span class="token number">100644</span> </span><span class="code-line">index 0000000<span class="token punctuation">..</span>ea956fe </span><span class="code-line">--- /dev/null </span><span class="code-line">+++ b/world.txt </span><span class="code-line">@@ -0,0 +1 @@ </span><span class="code-line">+test older commit fixup </span></code></pre></div><p>OK了, 目的是达到了。但是,是不是特别麻烦?</p><h2 id="fixup神技出世"><a href="#fixup神技出世" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>fixup神技出世</h2><p>我们给Git配置文件(<code>.gitconfig</code>)增加一个叫<code>fixup</code>的alias操作:</p><blockquote><p>老灯修正: Debian/Ubuntu 默认使用Dash(POSIX兼容)作为默认的sh, 不像Fedora/CentOS 使用的是bash(支持一些非POSIX的特性), 因此为了兼容性更好,我们不能使用非POSIX的<code>${@:2}</code></p><p><code>GIT_EDITOR</code>的优先级最高,原<code>EDITOR=true</code>换成<code>GIT_EDITOR=true</code>兼容性更好</p></blockquote><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">alias</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token comment">#fixup = &quot;!f() { TARGET=$(git rev-parse &quot;$1&quot;); git commit --fixup=$TARGET ${@:2} &amp;&amp; EDITOR=true git rebase -i --autostash --autosquash $TARGET^; }; f&quot;</span> </span><span class="code-line"> <span class="token attr-name key">fixup</span> <span class="token punctuation">=</span> <span class="token attr-value value">&quot;<span class="token inner-value">!f() { TARGET=$(git rev-parse \&quot;$1\&quot;); shift; git commit --fixup=$TARGET ${@} &amp;&amp; GIT_EDITOR=true git rebase -i --autostash --autosquash $TARGET^; }; f</span>&quot;</span> </span></code></pre></div><p>有了这个<code>fixup</code>之后,我们可以非常方便的修改任意提交.</p><p>操作步骤:</p><ol><li>做修改</li><li>git add -u</li><li><code>git fixup 需要修改的commit id</code></li></ol><p>没错, 三步就搞定了。</p><p>好了,现在假设我们还是要修改关于world.txt那个提交。我们可以直接就开始修改了:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">echo</span> <span class="token string">&#x27;quick fixup demo&#x27;</span> <span class="token operator">&gt;</span> world.txt </span><span class="code-line"><span class="token function">git</span> <span class="token function">add</span> <span class="token parameter variable">-u</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 先看一下我们要修改的是哪个commit</span> </span><span class="code-line">❯ <span class="token function">git</span> lg1 </span><span class="code-line">* 3562e20 - <span class="token punctuation">(</span><span class="token number">16</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> README.md - 荒野無燈 <span class="token punctuation">(</span>HEAD -<span class="token operator">&gt;</span> master<span class="token punctuation">)</span> </span><span class="code-line">* ade3438 - <span class="token punctuation">(</span><span class="token number">7</span> minutes ago<span class="token punctuation">)</span> update world.txt - 荒野無燈 </span><span class="code-line">* a956ae3 - <span class="token punctuation">(</span><span class="token number">29</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> hello.txt - 荒野無燈 </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># OK, 找到了,我们要修改的是 ade3438</span> </span><span class="code-line">❯ <span class="token function">git</span> fixup ade3438 </span><span class="code-line"><span class="token punctuation">[</span>master 6b1d0b1<span class="token punctuation">]</span> fixup<span class="token operator">!</span> update world.txt </span><span class="code-line"> <span class="token number">1</span> <span class="token function">file</span> changed, <span class="token number">1</span> insertion<span class="token punctuation">(</span>+<span class="token punctuation">)</span>, <span class="token number">1</span> deletion<span class="token punctuation">(</span>-<span class="token punctuation">)</span> </span><span class="code-line">Successfully rebased and updated refs/heads/master. </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 再看下commit history, 可以看到被修改的commit及其之后的commit的commit id全rewrite了</span> </span><span class="code-line">❯ <span class="token function">git</span> lg1 </span><span class="code-line">* a2bb0e7 - <span class="token punctuation">(</span><span class="token number">17</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> README.md - 荒野無燈 <span class="token punctuation">(</span>HEAD -<span class="token operator">&gt;</span> master<span class="token punctuation">)</span> </span><span class="code-line">* 6b02dd5 - <span class="token punctuation">(</span><span class="token number">8</span> minutes ago<span class="token punctuation">)</span> update world.txt - 荒野無燈 </span><span class="code-line">* a956ae3 - <span class="token punctuation">(</span><span class="token number">29</span> minutes ago<span class="token punctuation">)</span> <span class="token function">add</span> hello.txt - 荒野無燈 </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># git show 6b02dd5 确认下修改效果</span> </span><span class="code-line"><span class="token function">diff</span> <span class="token parameter variable">--git</span> a/world.txt b/world.txt </span><span class="code-line">new <span class="token function">file</span> mode <span class="token number">100644</span> </span><span class="code-line">index 0000000<span class="token punctuation">..</span>5db415f </span><span class="code-line">--- /dev/null </span><span class="code-line">+++ b/world.txt </span><span class="code-line">@@ -0,0 +1 @@ </span><span class="code-line">+quick fixup demo </span></code></pre></div><p>这个超级实用的alias我是在 <a href="https://blog.filippo.io/git-fixup-amending-an-older-commit/">https://blog.filippo.io/git-fixup-amending-an-older-commit/</a> 看到的。</p><p>作者是意大利籍的<a href="https://twitter.com/FiloSottile">Filippo Valsorda</a>, Google安全领域的专家,Go 团队的 security lead.</p><blockquote><p>use git fixup COMMIT to change a specific &quot;COMMIT&quot;, exactly like you would use <code>git commit --amend</code> to change the latest one. You can use all <code>git commit</code> arguments, like <code>-a</code>, <code>-p</code> and <em>filenames</em>. It will respect your index, so you can use git add. It won&#x27;t touch the changes you are not committing.</p></blockquote><p>没错,除了刚才的用法,这个<code>fixup</code>还可以加参数,比如:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">git</span> fixup HEAD^ Makefile </span></code></pre></div><h2 id="工作原理"><a href="#工作原理" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>工作原理</h2><p>我们把这个命令拆解开来, 可以发现实际上它是两条Git命令的结合。</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token attr-name key">TARGET</span><span class="token punctuation">=</span><span class="token attr-value value">$(git rev-parse &quot;$1&quot;); \</span> </span><span class="code-line"><span class="token attr-name key">git commit --fixup</span><span class="token punctuation">=</span><span class="token attr-value value">$TARGET ${@:2} &amp;&amp; \</span> </span><span class="code-line"><span class="token attr-name key">EDITOR</span><span class="token punctuation">=</span><span class="token attr-value value">true git rebase -i --autostash --autosquash $TARGET^</span> </span></code></pre></div><p>第一行<code>TARGET=$(git rev-parse &quot;$1&quot;)</code> 只是设置一下环境变量,它记住了我们要修改的是哪个commit. 注意这里用到了<code>rev-parse</code>解析出commit id, 因为我们输入的需要修改的commit, 可能是 <code>@</code> 或 <code>HEAD</code>, 或 <code>@^</code> 及 <code>@^^</code> 这样的东西。 而<code>HEAD^</code>或 <code>@^</code> 之类的会在真实的HEAD变动时其值随之变动的,所以,用<code>rev-parse</code>是必要的。要不然我们后面要用到<code>$TARGET^</code>参数值就可能是错的。</p><p>要理解<code>git commit --fixup=$TARGET ${@:2}</code>, 首先我们要理解<code>${@:2}</code> 是个啥。</p><p>根据文档 <a href="http://tldp.org/LDP/abs/html/internalvariables.html#APPREF">http://tldp.org/LDP/abs/html/internalvariables.html#APPREF</a></p><blockquote><p><code>$#</code> Number of command-line arguments [4] or positional parameters (see Example 36-2)</p><p><code>$*</code> All of the positional parameters, seen as a single word Note: &quot;<code>$*</code>&quot; must be quoted.</p><p><code>$@</code> Same as <code>$*</code>, but each parameter is a quoted string, that is, the parameters are passed on intact, without interpretation or expansion. This means, among other things, that each parameter in the argument list is seen as a separate word. Note: Of course, &quot;<code>$@</code>&quot; should be quoted.</p></blockquote><p>又见 <a href="http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html#sect_03_02_05">http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html#sect_03_02_05</a></p><blockquote><p><code>$*</code> Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the IFS special variable. <code>$@</code> Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. <code>$*</code> vs. <code>$@</code> The implementation of &quot;<code>$*</code>&quot; has always been a problem and realistically should have been replaced with the behavior of &quot;<code>$@</code>&quot;. In almost every case where coders use &quot;<code>$*</code>&quot;, they mean &quot;<code>$@</code>&quot;. &quot;<code>$*</code>&quot; Can cause bugs and even security holes in your software.</p></blockquote><p><code>$@</code> 表示的是Bash里面的位置参数,但是它跟<code>$*</code>还是有些不同的。 简单来说,<code>$*</code>是单个的长字符串,而<code>$@</code>实际上是一个数组。</p><p>所以, <code>${@:2}</code> 实际上是访问 <code>@</code>这个数组, 根据Bash的语法, <code>${array[@]:first:length}</code>, 由于这里省略了length,因此默认表示到末尾。</p><p>所以, <code>${@:2}</code>表示从index为2开始的所有位置参数。</p><p>对于<code>git fixup xxx</code>来说,<code>${@:0}</code> 为整个命令,<code>${@:1}</code> 为除去<code>git</code>本身之后的部分,自然<code>${@:2}</code>就表示git命令的第二个(包含)及之后的参数,而这些参数都会传递给<code>git commit</code>命令。</p><p>然后,我们再看看<code>--fixup</code>参数的作用:</p><blockquote><p><code>--fixup=&lt;commit&gt;</code> Construct a commit message for use with rebase --autosquash. The commit message will be the subject line from the specified commit with a prefix of &quot;fixup! &quot;. See git-rebase(1) for details.</p></blockquote><p>它是用于构造一个commit消息给<code>rebase --autosquash</code>使用的,这个commit消息的subject(标题)为指定commit的标题前面加上 &quot;fixup! &quot;.</p><p>比如commit <code>6b02dd55fcc392fac951e7cba6b60cf1bd60d427</code>的subject是<code>update world.txt</code>, 我们执行一下,subject就会自动变成<code>fixup! update world.txt</code>, 如:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">git</span> commit <span class="token parameter variable">--fixup</span><span class="token operator">=</span>6b02dd55fcc392fac951e7cba6b60cf1bd60d427 </span><span class="code-line"><span class="token punctuation">[</span>master 66f03bc<span class="token punctuation">]</span> fixup<span class="token operator">!</span> update world.txt </span><span class="code-line"> <span class="token number">1</span> <span class="token function">file</span> changed, <span class="token number">1</span> insertion<span class="token punctuation">(</span>+<span class="token punctuation">)</span> </span></code></pre></div><p>然后,<code>EDITOR=true git rebase -i --autostash --autosquash $TARGET^</code> 启动了一个交互式的<code>rebase</code>操作(<code>git rebase -i</code>), 并且带了<code>--autosquash</code>参数,它会标记所有提交信息里有<code>fixup! FOO</code>之类的字符的commit自动以<code>fixup</code>的方式合并到名为<code>FOO</code>的commit记录. <code>fixup</code>跟<code>squash</code>类似,只不过<code>fixup</code>会忽略提交信息。没错,这个<code>--autosquash</code>就是为<code>git commit --fixup</code>而生的。 如果你不是经常做rebase操作,可能会不是很容易理解这里。</p><p><code>--autostash</code>的作用又是啥呢?它确保在rebase之前所有未提交的修改都自动<code>stash</code>, 而在rebase完成之后,这些修改又会自动从stash栈里面弹出来。 (没错,又涉及到stash命令了,如果不太了解,赶紧查手册看看吧)</p><p>rebase操作都要有一个base commit的,一般来说,这个base就是我们要操作的那个提交的前一个提交,因此是<code>$TARGET^</code>(<code>^</code>符号表示在它左边的commit往前一个提交)。</p><p><code>EDITOR=true</code>在这里也是一个绝妙的存在。别看它看上去不起眼,好像在设置一个什么东西为“真”一样。如果你这样想可错了。 Git在进行交互式rebase的时候,需要调用编辑器弹出一个列表,让你编辑哪个commit要<code>f</code>(fixup), 哪个要<code>s</code>(squash),哪个要直接删除等。 因此,这里实际上是临时把Git的编辑器设置成了一个名为<code>true</code>的命令:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">which</span> <span class="token boolean">true</span> </span><span class="code-line">/usr/bin/true </span></code></pre></div><p>可以看到,在一般的Linux发行版里,这个命令的位置为<code>/usr/bin/true</code>,但是也有可能有不同,因此这里没有使用绝对路径,而是直接给出了命令名称。 <code>true</code> 命令的运行效果就是它执行完马上退出了,其退出代码为 0 (跟false正好相反,false是exit code 为1)。 这里我们当然不能用false,因为false会返回1, Git会认为这个编辑器出问题,意外退出了.</p><p>另外,这里之所以能用<code>EDITOR=true</code>的原因是,所有信息都不需要我们再次编辑,Git原来也只是给你看一眼而已,然后让你保存退出(由于不存在修改,其实也不存在要保存)。 这跟我们手动rebase的情况是不同的。</p><p>所以,这里<code>EDITOR=true</code>的作用是,避免Git给你显示一个交互式rebase操作的列表,然后还要你手动按一次<code>w</code>保存。</p><p>然后,将这些命令组合起来,包裹成一个Bash 函数, 因为只有这样,才方便访问像 <code>$1</code> 和 <code>${@:2}</code> 之类的位置参数。</p><p>最后,在最前面加一个<code>!</code>, 它就变成了一个shell alias了,能为Git所用了.</p><h2 id="troubleshoot"><a href="#troubleshoot" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Troubleshoot</h2><h3 id="交互式窗口还是弹出来了"><a href="#交互式窗口还是弹出来了" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>交互式窗口还是弹出来了</h3><p>也许你也是像老灯一样,给Git显式地指定了editor, 然后发现,<code>EDITOR=true</code>没生效啊,Git还是每次在我<code>fixup</code>时弹出一个黑东东来烦我。 老灯起初也是郁闷了好久,直到有一天突然想明白,文件配置的优先级,可能比环境变量配置的优先级要高。</p><p>我们还是看下文档确认下吧 <a href="https://git-scm.com/docs/git-var#Documentation/git-var.txt-GITEDITOR">https://git-scm.com/docs/git-var#Documentation/git-var.txt-GITEDITOR</a></p><blockquote><p>GIT_EDITOR</p><p>Text editor for use by Git commands. The value is meant to be interpreted by the shell when it is used. Examples: ~/bin/vi, <code>$SOME_ENVIRONMENT_VARIABLE</code>, &quot;C:\Program Files\Vim\gvim.exe&quot; --nofork. The order of preference is the <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mi>I</mi><msub><mi>T</mi><mi>E</mi></msub><mi>D</mi><mi>I</mi><mi>T</mi><mi>O</mi><mi>R</mi><mi>e</mi><mi>n</mi><mi>v</mi><mi>i</mi><mi>r</mi><mi>o</mi><mi>n</mi><mi>m</mi><mi>e</mi><mi>n</mi><mi>t</mi><mi>v</mi><mi>a</mi><mi>r</mi><mi>i</mi><mi>a</mi><mi>b</mi><mi>l</mi><mi>e</mi><mo separator="true">,</mo><mi>t</mi><mi>h</mi><mi>e</mi><mi>n</mi><mi>c</mi><mi>o</mi><mi>r</mi><mi>e</mi><mi mathvariant="normal">.</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>t</mi><mi>o</mi><mi>r</mi><mi>c</mi><mi>o</mi><mi>n</mi><mi>f</mi><mi>i</mi><mi>g</mi><mi>u</mi><mi>r</mi><mi>a</mi><mi>t</mi><mi>i</mi><mi>o</mi><mi>n</mi><mo separator="true">,</mo><mi>t</mi><mi>h</mi><mi>e</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">GIT_EDITOR environment variable, then core.editor configuration, then </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:.8889em;vertical-align:-.1944em"></span><span class="mord mathnormal">G</span><span class="mord mathnormal" style="margin-right:.07847em">I</span><span class="mord"><span class="mord mathnormal" style="margin-right:.13889em">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:.3283em"><span style="top:-2.55em;margin-left:-.1389em;margin-right:.05em"><span class="pstrut" style="height:2.7em"></span><span class="mtight reset-size6 size3 sizing"><span class="mord mathnormal mtight" style="margin-right:.05764em">E</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:.15em"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:.02778em">D</span><span class="mord mathnormal" style="margin-right:.07847em">I</span><span class="mord mathnormal" style="margin-right:.00773em">TOR</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal" style="margin-right:.03588em">v</span><span class="mord mathnormal">i</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">nm</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:.03588em">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:.02778em">r</span><span class="mord mathnormal">iab</span><span class="mord mathnormal" style="margin-right:.01968em">l</span><span class="mord mathnormal">e</span><span class="mpunct">,</span><span class="mspace" style="margin-right:.1667em"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">h</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">core</span><span class="mord">.</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">t</span><span class="mord mathnormal">orco</span><span class="mord mathnormal">n</span><span class="mord mathnormal" style="margin-right:.10764em">f</span><span class="mord mathnormal">i</span><span class="mord mathnormal">gu</span><span class="mord mathnormal" style="margin-right:.02778em">r</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">i</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mpunct">,</span><span class="mspace" style="margin-right:.1667em"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">h</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span></span></span></span></span>VISUAL, then $EDITOR, and then the default chosen at compile time, which is usually vi.</p></blockquote><p>根据Git文档,这个编辑器配置的优先级是:</p><blockquote><p>GIT_EDITOR &gt; core.editor &gt; VISUAL &gt; EDITOR &gt; vi</p></blockquote><p>因此,为了在alias中临时地使用<code>true</code>作为编辑器,我们应该修正一下这个alias, 将<code>EDITOR=true</code>替换成<code>GIT_EDITOR=true</code>, 问题解决。</p><h3 id="git-commit-id被重写"><a href="#git-commit-id被重写" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Git commit id被重写</h3><p>没错,由于这里实际上是一个自动的rebase操作,所以你要知晓它的副使用:</p><p>所有在<code>$TARGET</code>之后(当然包括<code>$TARGET</code>本身)的commit id都将被重写. 这是git rebase的特性,不是bug.</p><p>如果你介意commit id的改变,此时你可能不会想要用这一招。</p><p>需要注意的是,如果某些commit已经被push到了远程仓库,那么这些commit最好不要再进行rebase, 除非你确认了团队中没有任何人pull了那些提交, 否则即使你用了强制push(<code>-f</code>参数)把rebase后重写之后的记录提交上去了,其它人在pull这些代码的时候也有可能会遇到无尽的冲突。</p><h3 id="常用alias"><a href="#常用alias" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>常用alias</h3><p>你上面命令中的<code>ci</code>啊,<code>lg1</code>啊,是个啥东西啊?</p><p>没错,这些是老灯日常使用的alias, 这里老灯也干脆一并把它们分享了。</p><p>注意,pager这里老灯使用了<a href="https://github.com/mookid/diffr">diffr</a></p><p><code>difftool</code> 和 <code>merge</code> 老灯默认用了开源的<a href="https://meldmerge.org/">meld</a></p><p>所有配置仅供参考,除非你明白你在做什么,否则不要直接copy全部配置。</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">user</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">name</span> <span class="token punctuation">=</span> <span class="token attr-value value">荒野無燈</span> </span><span class="code-line"> <span class="token attr-name key">email</span> <span class="token punctuation">=</span> <span class="token attr-value value">不告诉你</span> </span><span class="code-line"> <span class="token attr-name key">signingkey</span> <span class="token punctuation">=</span> <span class="token attr-value value">不告诉你</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">color</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">ui</span> <span class="token punctuation">=</span> <span class="token attr-value value">true</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">core</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token comment"># editor = vim -f</span> </span><span class="code-line"> <span class="token comment">#pager = $HOME/.yarn/bin/diff-so-fancy | less --tabs=4 -RFX</span> </span><span class="code-line"> <span class="token attr-name key">autocrlf</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"> <span class="token attr-name key">quotepath</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">pager</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">log</span> <span class="token punctuation">=</span> <span class="token attr-value value">diffr | less -RFX</span> </span><span class="code-line"> <span class="token attr-name key">show</span> <span class="token punctuation">=</span> <span class="token attr-value value">diffr | less -RFX</span> </span><span class="code-line"> <span class="token attr-name key">diff</span> <span class="token punctuation">=</span> <span class="token attr-value value">diffr | less -RFX</span> </span><span class="code-line"> <span class="token attr-name key">branch</span> <span class="token punctuation">=</span> <span class="token attr-value value">less -RFX</span> </span><span class="code-line"> <span class="token attr-name key">tag</span> <span class="token punctuation">=</span> <span class="token attr-value value">less -RFX</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">interactive</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">diffFilter</span> <span class="token punctuation">=</span> <span class="token attr-value value">diffr</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">diff</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">tool</span> <span class="token punctuation">=</span> <span class="token attr-value value">bc3</span> </span><span class="code-line"> <span class="token attr-name key">renameLimit</span> <span class="token punctuation">=</span> <span class="token attr-value value">37901</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">difftool</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">prompt</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">difftool &quot;meld&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token comment">#path = /usr/bin/meld</span> </span><span class="code-line"> <span class="token attr-name key">cmd</span> <span class="token punctuation">=</span> <span class="token attr-value value">meld $LOCAL $REMOTE</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">difftool &quot;bc3&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">path</span> <span class="token punctuation">=</span> <span class="token attr-value value">/usr/bin/bcompare</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">difftool &quot;vimdiff&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">cmd</span> <span class="token punctuation">=</span> <span class="token attr-value value">gvimdiff $REMOTE $LOCAL $BASE</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">merge</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">tool</span> <span class="token punctuation">=</span> <span class="token attr-value value">meld</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">mergetool</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">prompt</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"> <span class="token attr-name key">keepbackup</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">mergetool &quot;bc3&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">path</span> <span class="token punctuation">=</span> <span class="token attr-value value">/usr/bin/bcompare</span> </span><span class="code-line"> <span class="token attr-name key">trustExitCode</span> <span class="token punctuation">=</span> <span class="token attr-value value">true</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">mergetool &quot;meld&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">path</span> <span class="token punctuation">=</span> <span class="token attr-value value">/usr/bin/meld</span> </span><span class="code-line"> <span class="token attr-name key">trustExitCode</span> <span class="token punctuation">=</span> <span class="token attr-value value">true</span> </span><span class="code-line"> <span class="token attr-name key">keepBackup</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"> <span class="token comment">#the first is the default</span> </span><span class="code-line"> <span class="token comment">#cmd = meld &quot;$LOCAL&quot; &quot;$BASE&quot; &quot;$REMOTE&quot; --output &quot;$MERGED&quot;</span> </span><span class="code-line"> <span class="token attr-name key">cmd</span> <span class="token punctuation">=</span> <span class="token attr-value value">meld $LOCAL $MERGED $REMOTE --output $MERGED</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">alias</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">co</span> <span class="token punctuation">=</span> <span class="token attr-value value">checkout</span> </span><span class="code-line"> <span class="token attr-name key">ci</span> <span class="token punctuation">=</span> <span class="token attr-value value">commit</span> </span><span class="code-line"> <span class="token attr-name key">st</span> <span class="token punctuation">=</span> <span class="token attr-value value">status</span> </span><span class="code-line"> <span class="token attr-name key">stn</span> <span class="token punctuation">=</span> <span class="token attr-value value">status -uno</span> </span><span class="code-line"> <span class="token attr-name key">br</span> <span class="token punctuation">=</span> <span class="token attr-value value">branch</span> </span><span class="code-line"> <span class="token attr-name key">cp</span> <span class="token punctuation">=</span> <span class="token attr-value value">cherry-pick</span> </span><span class="code-line"> <span class="token attr-name key">unstage</span> <span class="token punctuation">=</span> <span class="token attr-value value">reset HEAD --</span> </span><span class="code-line"> <span class="token attr-name key">dt</span> <span class="token punctuation">=</span> <span class="token attr-value value">difftool</span> </span><span class="code-line"> <span class="token attr-name key">dtd</span> <span class="token punctuation">=</span> <span class="token attr-value value">difftool --dir-diff</span> </span><span class="code-line"> <span class="token attr-name key">mt</span> <span class="token punctuation">=</span> <span class="token attr-value value">mergetool</span> </span><span class="code-line"> <span class="token attr-name key">last</span> <span class="token punctuation">=</span> <span class="token attr-value value">log -1 HEAD</span> </span><span class="code-line"> <span class="token attr-name key">lg1</span> <span class="token punctuation">=</span> <span class="token attr-value value">log --graph --abbrev-commit --decorate --date-order --date=relative --format=format:&#x27;%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %aN%C(reset)%C(bold yellow)%d%C(reset)&#x27; --all</span> </span><span class="code-line"> <span class="token attr-name key">lg2</span> <span class="token punctuation">=</span> <span class="token attr-value value">log --graph --abbrev-commit --decorate --date-order --format=format:&#x27;%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n&#x27;&#x27; %C(white)%s%C(reset) %C(dim white)- %aN%C(reset)&#x27; --all</span> </span><span class="code-line"> <span class="token attr-name key">lg</span> <span class="token punctuation">=</span> <span class="token attr-value value">!git lg1</span> </span><span class="code-line"> <span class="token attr-name key">up</span> <span class="token punctuation">=</span> <span class="token attr-value value">&quot;<span class="token inner-value">!git remote update -p; git merge --ff-only @{u}</span>&quot;</span> </span><span class="code-line"> <span class="token attr-name key">zipmod</span> <span class="token punctuation">=</span> <span class="token attr-value value">!git archive -o update.zip HEAD $(git diff --name-only HEAD^)</span> </span><span class="code-line"> <span class="token attr-name key">dsf</span> <span class="token punctuation">=</span> <span class="token attr-value value">&quot;<span class="token inner-value">!f() { [ -z \&quot;$GIT_PREFIX\&quot; ] || cd \&quot;$GIT_PREFIX\&quot; &amp;&amp; git diff --color \&quot;$@\&quot; | diff-so-fancy | less --tabs=4 -RFX; }; f</span>&quot;</span> </span><span class="code-line"> <span class="token attr-name key">findandblame</span> <span class="token punctuation">=</span> <span class="token attr-value value">&quot;<span class="token inner-value">!f() { git blame $(git log --pretty=%H --diff-filter=AM -1 -- \&quot;$1\&quot;) -- \&quot;$1\&quot;; }; f</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token attr-name key">find-merge</span> <span class="token punctuation">=</span> <span class="token attr-value value">&quot;<span class="token inner-value">!sh -c &#x27;commit=$0 &amp;&amp; branch=${1:-HEAD} &amp;&amp; (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2&#x27;</span>&quot;</span> </span><span class="code-line"> <span class="token attr-name key">show-merge</span> <span class="token punctuation">=</span> <span class="token attr-value value">!sh -c &#x27;merge=$(git find-merge $0 $1) &amp;&amp; [ -n \&quot;$merge\&quot; ] &amp;&amp; git show $merge&#x27;</span> </span><span class="code-line"> <span class="token attr-name key">lm</span> <span class="token punctuation">=</span> <span class="token attr-value value">log --use-mailmap</span> </span><span class="code-line"> <span class="token attr-name key">pushall</span> <span class="token punctuation">=</span> <span class="token attr-value value">!git remote | xargs -L1 git push --all</span> </span><span class="code-line"> <span class="token attr-name key">cs</span> <span class="token punctuation">=</span> <span class="token attr-value value">commit --signoff</span> </span><span class="code-line"> <span class="token comment"># https://blog.filippo.io/git-fixup-amending-an-older-commit/</span> </span><span class="code-line"> <span class="token attr-name key">fixup</span> <span class="token punctuation">=</span> <span class="token attr-value value">&quot;<span class="token inner-value">!f() { TARGET=$(git rev-parse \&quot;$1\&quot;); shift; git commit --fixup=$TARGET ${@} &amp;&amp; GIT_EDITOR=true git rebase -i --autostash --autosquash $TARGET^; }; f</span>&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">pull</span><span class="token punctuation">]</span></span> </span><span class="code-line"><span class="token comment"># rebase = true</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">color &quot;diff-highlight&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">oldNormal</span> <span class="token punctuation">=</span> <span class="token attr-value value">red bold</span> </span><span class="code-line"> <span class="token attr-name key">oldHighlight</span> <span class="token punctuation">=</span> <span class="token attr-value value">red bold 52</span> </span><span class="code-line"> <span class="token attr-name key">newNormal</span> <span class="token punctuation">=</span> <span class="token attr-value value">green bold</span> </span><span class="code-line"> <span class="token attr-name key">newHighlight</span> <span class="token punctuation">=</span> <span class="token attr-value value">green bold 22</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">filter &quot;lfs&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">clean</span> <span class="token punctuation">=</span> <span class="token attr-value value">git-lfs clean -- %f</span> </span><span class="code-line"> <span class="token attr-name key">smudge</span> <span class="token punctuation">=</span> <span class="token attr-value value">git-lfs smudge -- %f</span> </span><span class="code-line"> <span class="token attr-name key">process</span> <span class="token punctuation">=</span> <span class="token attr-value value">git-lfs filter-process</span> </span><span class="code-line"> <span class="token attr-name key">required</span> <span class="token punctuation">=</span> <span class="token attr-value value">true</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">filter &quot;dater&quot;</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">smudge</span> <span class="token punctuation">=</span> <span class="token attr-value value">expand_date</span> </span><span class="code-line"> <span class="token attr-name key">clean</span> <span class="token punctuation">=</span> <span class="token attr-value value">perl -pe \&quot;s/\\\\\\$Date[^\\\\\\$]*\\\\\\$/\\\\\\$Date\\\\\\$/\&quot;</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">gc</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">autoDetach</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"><span class="token comment">#[url &quot;[email protected]:&quot;]</span> </span><span class="code-line"><span class="token comment"># insteadOf = https://github.com/</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># git clone https://bitbucket.org/ 时默认替换成ssh访问</span> </span><span class="code-line"><span class="token comment"># [url &quot;[email protected]:&quot;]</span> </span><span class="code-line"><span class="token comment"># insteadOf = https://bitbucket.org/</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># http 代理设置</span> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">http</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">lowSpeedLimit</span> <span class="token punctuation">=</span> <span class="token attr-value value">1000</span> </span><span class="code-line"> <span class="token attr-name key">lowSpeedTime</span> <span class="token punctuation">=</span> <span class="token attr-value value">300</span> </span><span class="code-line"> <span class="token attr-name key">proxy</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://127.0.0.1:7070</span> </span><span class="code-line"> <span class="token attr-name key">sslVerify</span> <span class="token punctuation">=</span> <span class="token attr-value value">false</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># [commit]</span> </span><span class="code-line"><span class="token comment"># gpgsign = true</span> </span><span class="code-line"> </span><span class="code-line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">tag</span><span class="token punctuation">]</span></span> </span><span class="code-line"> <span class="token attr-name key">forcesignannotated</span> <span class="token punctuation">=</span> <span class="token attr-value value">true</span> </span></code></pre></div><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://blog.filippo.io/git-fixup-amending-an-older-commit/">https://blog.filippo.io/git-fixup-amending-an-older-commit/</a></p><p><a href="http://stackoverflow.com/questions/6217156/break-a-previous-commit-into-multiple-commits">http://stackoverflow.com/questions/6217156/break-a-previous-commit-into-multiple-commits</a></p><p><a href="http://tldp.org/LDP/abs/html/internalvariables.html#APPREF">http://tldp.org/LDP/abs/html/internalvariables.html#APPREF</a></p><p><a href="http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html#sect_03_02_05">http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html#sect_03_02_05</a></p><p><a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration#_core_editor">https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration#_core_editor</a></p> Sat, 16 May 2020 11:21:52 GMT ttyS3 gitamendfixuprebase https://ttys3.dev/blog/how-to-deploy-static-blog-to-aws-s3 如何部署静态博客到AWS S3 https://ttys3.dev/blog/how-to-deploy-static-blog-to-aws-s3 <h2 id="0-aws-s3介绍"><a href="#0-aws-s3介绍" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>0. AWS S3介绍</h2><p>Amazon S3 Endpoints可以在这里查看 <a href="https://docs.aws.amazon.com/general/latest/gr/s3.html">https://docs.aws.amazon.com/general/latest/gr/s3.html</a> S3 在大部分地区都有节点,但是也不是所有节点都有。</p><p>S3是对象存储,默认情况下是不能用来做静态网站的,但是可以通过启用website config来达到目的。</p><p>这里要注意的是,<a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteEndpoints.html">Website endpoint</a> 和普通的REST API访问时,其使用的endpoint是不同的。</p><table><thead><tr><th>REST API Endpoint</th><th>Website Endpoint</th></tr></thead></table><p>bucket-name.s3.区域代码.amazonaws.com | bucket-name.s3-website.区域代码.amazonaws.com</p><p><code>Website Endpoint</code> 还有另一种可以直接用<code>-</code>将区域代码连起来,形成<code>s3-website-区域代码</code> 这样: <code>bucket-name.s3-website-区域代码.amazonaws.com</code></p><p>老灯还是觉得用点号法更明了一些。</p><p>网站终端节点和 REST API 终端节点之间的主要区别</p><p><a href="https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/dev/WebsiteEndpoints.html">https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/dev/WebsiteEndpoints.html</a></p><table><thead><tr><th>主要区别</th><th>REST API 终端节点</th><th>网站终端节点</th></tr></thead><tbody><tr><td>访问控制</td><td>同时支持公有和私有内容</td><td>仅支持公开可读的内容</td></tr><tr><td>错误消息处理</td><td>返回 XML 格式的错误响应</td><td>返回 HTML 文档</td></tr><tr><td>重定向支持</td><td>不适用</td><td>同时支持对象级和存储桶级重定向</td></tr><tr><td>支持的请求</td><td>支持所有存储桶和对象操作</td><td>仅支持对象上的 GET 和 HEAD 请求</td></tr><tr><td>对存储桶根级的 GET 和 HEAD 请求的响应</td><td>返回存储桶中对象键的列表</td><td>返回在网站配置中指定的索引文档</td></tr><tr><td>安全套接字层 (SSL) 支持</td><td>支持 SSL 连接</td><td>不支持 SSL 连接</td></tr></tbody></table><p>如果你有非公开内容要存储,那么肯定不能用Website endpoint. 另外,AWS S3 的 Website endpoint有个缺点,不支持 SSL 连接。当然我们一般直接在前面套个CloudFlare 自动SSL了。</p><h2 id="1创建bucket和ws-config"><a href="#1创建bucket和ws-config" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1.创建bucket和ws config</h2><p>为了能绑定自己的域名,bucket的名字我们要设置为域名。 假如我们需要用到的博客域名是 <code>test001.ttys3.net</code></p><p>这里我们用到了<code>s3cmd</code> <a href="https://github.com/s3tools/s3cmd">https://github.com/s3tools/s3cmd</a> , 如果没有安装的要先安装一下。 Fedora直接 <code>sudo dnf install -y s3cmd</code> 即可。其它系统可参数s3cmd的文档下载安装。 如果不习惯命令行,下面这些命令行操作都可以直接登录AWS S3控制台通过点击鼠标完成,这里我就不截图了。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 创建 bucket</span> </span><span class="code-line">s3cmd mb s3://test001.ttys3.net </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 创建website config</span> </span><span class="code-line">ws-create --ws-index<span class="token operator">=</span>index.html --ws-error<span class="token operator">=</span><span class="token number">404</span>.html s3://test001.ttys3.net </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 查看下ws info</span> </span><span class="code-line">ws-info s3://test001.ttys3.net </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 上传内容</span> </span><span class="code-line"><span class="token comment"># 我们先随便上传两个文件</span> </span><span class="code-line">s3cmd put index.html <span class="token number">404</span>.html s3://test001.ttys3.net <span class="token parameter variable">-P</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 如果是部署hugo站点,可以直接用sync</span> </span><span class="code-line">s3cmd --no-mime-magic --acl-public --delete-removed --delete-after <span class="token function">sync</span> public/ s3://test001.ttys3.net </span></code></pre></div><h2 id="2-配置访问策略"><a href="#2-配置访问策略" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. 配置访问策略</h2><p>现在已经可以访问 <code>http://test001.ttys3.net.s3-website.us-west-1.amazonaws.com/index.html</code> 了。</p><p>但是,还不能直接访问 <code>http://test001.ttys3.net.s3-website.us-west-1.amazonaws.com/</code>。</p><p>默认情况下,创建了website配置后,<code>block public access</code>默认是全部没有勾选的,即允许全部公开访问。</p><p>所以,我们只需要再设置一下<code>bucket policy</code>就好了。</p><p>登录s3控制台 <a href="https://console.aws.amazon.com/s3/">https://console.aws.amazon.com/s3/</a> , 在Buckets列表中点击你要设置的bucket名称, 然后依次进入 Permissions - Bucket Policy, 然后在Bucket policy editor里粘贴如下内容(注意这里的<code>test001.ttys3.net</code>要换成你自己的bucket name)并保存:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;Version&quot;</span><span class="token operator">:</span> <span class="token string">&quot;2012-10-17&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;Statement&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;Sid&quot;</span><span class="token operator">:</span> <span class="token string">&quot;PublicReadGetObject&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;Effect&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Allow&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;Principal&quot;</span><span class="token operator">:</span> <span class="token string">&quot;*&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;Action&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&quot;s3:GetObject&quot;</span> </span><span class="code-line"> <span class="token punctuation">]</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;Resource&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token string">&quot;arn:aws:s3:::test001.ttys3.net/*&quot;</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>设置成功后,Permissions 和 Bucket Policy 上面会加上<code>public</code>的黄色标签。</p><div><img alt="" src="https://ttys3.dev/static/assets/aws-s3-bucket-acl-public-2020-05-15-04-23-02-YIEPKB42.png" width="1962" height="1326"/></div><p>此部分主要参考 <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteAccessPermissionsReqd.html">https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteAccessPermissionsReqd.html</a></p><p>这样设置以后,我们的网站就正常了,访问<code>/</code>会自动serve <code>index.html</code>, 访问不存在的文件会自动serve <code>404.html</code>.</p><div><img alt="" src="https://ttys3.dev/static/assets/aws-s3-ws-hello-2020-05-15-04-33-54-4BKDBUHM.png" width="1480" height="406"/></div><p>随便访问个不存在的文件:</p><div><img alt="" src="https://ttys3.dev/static/assets/aws-ws-error-file-2020-05-15-04-34-31-NAOGBBO6.png" width="1582" height="428"/></div><h2 id="3-绑定域名"><a href="#3-绑定域名" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. 绑定域名</h2><p>将 <code>test001.ttys3.net</code> CNAME到 <code>test001.ttys3.net.s3-website.us-west-1.amazonaws.com</code> 即可。 然后就能正常通过<code>http://test001.ttys3.net</code> 来访问了。 注意,前面已经说过了,Website endpoint是不支持https访问的,如果需要https,可以用AWS自家的cloudfront 或者 用 Cloudflare.</p><h2 id="4-hugo站点部署"><a href="#4-hugo站点部署" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4. hugo站点部署</h2><p>在hugo站点目录下(与<code>config.toml</code>同级那个目录)新建一文件<code>deploy.sh</code>, 内容如下:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token important shebang">#!/bin/sh</span> </span><span class="code-line"> </span><span class="code-line">s3cmd --no-mime-magic --acl-public --delete-removed --delete-after <span class="token function">sync</span> <span class="token punctuation">\</span> </span><span class="code-line">public/ s3://test001.ttys3.net </span></code></pre></div><p><code>test001.ttys3.net</code>记得替换成你自己的bucket name.</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">chmod</span> a+rx deploy.sh </span></code></pre></div><p>部署很简单,执行<code>deploy.sh</code> 即可:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">./deploy.sh </span></code></pre></div><p>--EOF</p> Thu, 14 May 2020 19:09:50 GMT ttyS3 awss3hugo https://ttys3.dev/blog/bat-a-cat-clone-with-wings bat -- 一只会飞的猫 https://ttys3.dev/blog/bat-a-cat-clone-with-wings <p>今天开始新建了一个叫 commandlinefu 的子目录(或者叫分类), 专门分享命令行相关的东西。</p><h2 id="5秒钟版本"><a href="#5秒钟版本" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>5秒钟版本</h2><p>这次要跟大家分享的是一个叫<code>bat</code> <a href="https://github.com/sharkdp/bat">https://github.com/sharkdp/bat</a> 的命令工具。</p><p>这个工具主要采用<a href="https://www.rust-lang.org/">Rust</a>编写, 它可以说是Linux里<code>cat</code>的克隆和增强版。</p><p>安装方法 <a href="https://github.com/sharkdp/bat#installation">https://github.com/sharkdp/bat#installation</a></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment">#Fedora</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> bat </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Windows</span> </span><span class="code-line"><span class="token comment"># Windows没有 choco的可以直接去 https://github.com/sharkdp/bat/releases 下载 bat-*-x86_64-pc-windows-msvc.zip</span> </span><span class="code-line">choco <span class="token function">install</span> bat </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Mac</span> </span><span class="code-line">brew <span class="token function">install</span> bat </span></code></pre></div><p>如果你不想看文章内容,只看这里就是,添加以下配置到<code>.zshrc</code>(或<code>.bashrc</code>):</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment">#bat https://github.com/sharkdp/bat</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">BAT_STYLE</span><span class="token operator">=</span>plain </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">BAT_THEME</span><span class="token operator">=</span><span class="token string">&quot;TwoDark&quot;</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">MANPAGER</span><span class="token operator">=</span><span class="token string">&quot;sh -c &#x27;col -bx | bat -l man -p&#x27;&quot;</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">MANROFFOPT</span><span class="token operator">=</span><span class="token string">&quot;-c&quot;</span> </span></code></pre></div><p>好了,到此,本文的5秒钟版本就已经结束了。</p><h2 id="关于名称"><a href="#关于名称" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>关于名称</h2><p>bat(中文可以译为“蝙蝠”),因为它功能跟cat类似,但是在cat的基本上有增强功能,所以就取名bat吧(b在c前面), 而cat可以翻译成猫的意思。 作者原文是“A cat(1) clone with wings. ”, 即带翅膀的克隆猫。 需要注意的是,cat的本意取不是取自猫,而是单词<code>concatenate</code>的缩写,而<code>concatenate</code>一般是“连接”的意思。</p><p>比如很多年前电脑书上流传的隐藏zip文件到图片里面, 这算是一种文件连接的操作:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">cat</span> mypic.jpg files.zip <span class="token operator">&gt;</span> amazing.jpg </span></code></pre></div><h2 id="主要亮点"><a href="#主要亮点" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>主要亮点</h2><h3 id="1-语法高亮"><a href="#1-语法高亮" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. 语法高亮</h3><p>作为程序员,大部分时候其实cat的文件都源码和配置文件, 这个时候bat用处可大了。 其高亮功能主要是使用了<a href="https://crates.io/crates/syntect">syntect</a>这个crate, 值得庆幸的是,syntect并没有自己发明轮子, 而是复用了<a href="http://www.sublimetext.com/docs/3/syntax.html#include-syntax">Sublime Text的语法高亮定义</a>. 好处显而易见, 可以兼容现有的ST高亮主题,或者稍做转换就可以拿来用。</p><div><img alt="bat-list-themes-cmd-2020-05-14-23-48-52.png" src="https://ttys3.dev/static/assets/bat-list-themes-cmd-2020-05-14-23-48-52-2XR5SO6D.png" width="1046" height="578"/></div><p>一些配色展示:</p><div><img alt="bat-syntax-hi-3-2020-05-14-23-45-37.png" src="https://ttys3.dev/static/assets/bat-syntax-hi-3-2020-05-14-23-45-37-HNTLF7QH.png" width="1048" height="1796"/></div><p>在它支持的配色里面(没有老灯最喜欢的Gruvbox),老灯比较喜欢<code>TwoDark</code>这个配色. 比较方便的是,bat支持使用环境变量来配置一些东西,比如老灯在<code>~/.zshrc</code>中是这样配置的:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">BAT_STYLE</span><span class="token operator">=</span>plain </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">BAT_THEME</span><span class="token operator">=</span><span class="token string">&quot;TwoDark&quot;</span> </span></code></pre></div><p>使用 <code>plain</code> 主要是避免bat在每列前面输出tab,因为默认是这样的:</p><div><img alt="bat-default-style-2020-05-15-00-12-53.png" src="https://ttys3.dev/static/assets/bat-default-style-2020-05-15-00-12-53-R3ZUUTN3.png" width="1362" height="494"/></div><div><img alt="bat-style-plain-2020-05-15-00-13-23.png" src="https://ttys3.dev/static/assets/bat-style-plain-2020-05-15-00-13-23-DHYF573M.png" width="1188" height="366"/></div><p>用bat高亮显示curl下载的shell脚本内容:</p><p><code>curl -fsSL https://deno.land/x/install/install.sh | bat</code></p><div><img alt="" src="https://ttys3.dev/static/assets/bat-hi-curl-result-2020-05-17-14-50-12-YI4XAMD3.png" width="1488" height="1800"/></div><h3 id="2-git集成"><a href="#2-git集成" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. Git集成</h3><p>如果你需要查看git修改内容,则 <code>BAT_STYLE</code> 配置至少要包含 <code>changes</code>:</p><div><img alt="bat-style-changes-2020-05-15-00-15-38.png" src="https://ttys3.dev/static/assets/bat-style-changes-2020-05-15-00-15-38-WAZEQZQJ.png" width="1224" height="410"/></div><h3 id="3-显示非打印字符"><a href="#3-显示非打印字符" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. 显示非打印字符</h3><div><img alt="bat-show-non-printable-2020-05-15-00-18-35.png" src="https://ttys3.dev/static/assets/bat-show-non-printable-2020-05-15-00-18-35-WG3GYJ6E.png" width="1240" height="364"/></div><h3 id="4-自动paging"><a href="#4-自动paging" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4. 自动paging</h3><p>这个分页我觉得还是不翻译好,所以就用了paging 如果是cat, 它会直接输出文件的所有输出,这个对于脚本来说无疑是必要的功能。 但是如果是人在终端查看一些东西呢?我们其实一次只能看一屏。所以,bat它会自动分页。 当计算到内容大于一屏时,它就会通过管道调用<code>less</code>来显示了.</p><p>如果要自定义pager, 可以这样:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">BAT_PAGER</span><span class="token operator">=</span><span class="token string">&quot;less -RFX&quot;</span> </span></code></pre></div><h3 id="5-跟其它工具集成"><a href="#5-跟其它工具集成" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>5. 跟其它工具集成</h3><p>当然,<code>bat</code> 也能像 <code>cat</code> 一样连接文件。</p><blockquote><p>Oh.. you can also use it to concatenate files wink. Whenever bat detects a non-interactive terminal (i.e. when you pipe into another process or into a file), bat will act as a drop-in replacement for cat and fall back to printing the plain file contents.</p></blockquote><p>这里要说一下, 官方说可以用作<code>Git</code>的diff工具,这里老灯倾向于推荐<a href="https://github.com/mookid/diffr">diffr</a>而不是使用这个cat的替代品。 毕竟术业有专攻。</p><h3 id="man"><a href="#man" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>man</h3><p>bat可以作为man的pager,然后将man高亮显示:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">MANPAGER</span><span class="token operator">=</span><span class="token string">&quot;sh -c &#x27;col -bx | bat -l man -p&#x27;&quot;</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable">MANROFFOPT</span><span class="token operator">=</span><span class="token string">&quot;-c&quot;</span> </span></code></pre></div><p>为什么要设置了<code>MANROFFOPT=&quot;-c&quot;</code>?如果遇到显示问题,比如像这样配色显示有问题,且多出了很多<code>1m</code>, <code>0m</code>之类的乱码:</p><div><img alt="bat-as-man-pager-problem-2020-05-15-01-02-21.png" src="https://ttys3.dev/static/assets/bat-as-man-pager-problem-2020-05-15-01-02-21-GFBFI4TQ.png" width="1584" height="922"/></div><p>加上<code>MANROFFOPT=&quot;-c&quot;</code>就没问题了:</p><div><img alt="bat-as-man-pager-2020-05-15-01-00-39.png" src="https://ttys3.dev/static/assets/bat-as-man-pager-2020-05-15-01-00-39-CIYPSJQS.png" width="1530" height="1086"/></div><p>这个<code>man</code>有了<code>bat</code>之后,真是炫。</p><p>其它的集成,老灯表示用处不是很大,感兴趣的可以自行去官网查看 <a href="https://github.com/sharkdp/bat#integration-with-other-tools">https://github.com/sharkdp/bat#integration-with-other-tools</a></p> Thu, 14 May 2020 14:45:21 GMT ttyS3 catrustmanpager https://ttys3.dev/blog/the-design-problem-of-lychee 为什么我说Lychee相册不是一个合格的相册系统 https://ttys3.dev/blog/the-design-problem-of-lychee <p>Lychee 是个很小巧的相册程序,采用PHP <a href="https://laravel.com/">Laravel</a>框架编写的。 由于用的pdo, 因此可以很方便的支持sqlite 和 mysql 等。</p><div><img alt="" src="https://ttys3.dev/static/assets/lychee-photo-viewer-EQKGWTQT.jpg" width="1070" height="921"/></div><p>老灯用过很多相册程序,包括古董级的ImageVue(后面改名叫X3 photo gallery了),Synology的<code>Photo Station</code>和 QNAP的<code>Photo Station</code>, 这些都挺好用的,但是都不免费。</p><p>老灯很早之前就做过<a href="https://hub.docker.com/r/80x86/lychee">Lychee的docker镜像</a>,主要是作为一个docker化的app给小钢炮系统使用, 当时的Lychee还不能支持SQLite数据库,老灯自行加上了。 同时老灯调试时也发现一些bug, 修复之后,也随便回馈给了官方,提交PRT合并到官方repo了。 不得不说,既然当初Lychee被老灯一眼看上了,它还是有那么些优点的。 比如小巧易用,界面简洁,但不失美观。虽然是用PHP写的,但是采用业界流行的框架编写,代码整洁规范且标准。</p><p>近期想到,好久没更新Lychee docker镜像了。是不是要更新一下? 然后发现Lychee已经由之前的3.x版本,都升级到4.x了。但是其实没多少变化。</p><p>根据我QQ群里朋友的反馈,和我自身的使用经验来看,Lychee确实存在不少问题。而且这些问题是功能设计上的,不是代码上的。</p><p>正如我在 <a href="https://github.com/ttys3/Lychee/issues/1">https://github.com/ttys3/Lychee/issues/1</a> 写的那样,Lychee的问题在于从设计上根本错了。</p><p><code>Lychee</code> is a very easy-to-use photo gallery. simple but beautiful.</p><p>However, it does have some design problems</p><p>problem 1: user uploaded filename should not randomized or got obfucated. when the file leaves the Lychee app, it should be remaining meaningful, not something like unix timestamp or md5 hash you never know what this file do. a file named <code>dog.jpg</code> is more meaningful than a file named <code>06d80eb0c50b49a509b49f2424e8c805.jpg</code></p><p>problem 2: source file should not treated like thumbnail in the same level. source file should put in standalone directory. while thumbnail should generated under a dot directory like <code>.lychee-thumb</code></p><p>problem 3: the photo importing feature, which is totally wrong designed while most usage case is, a user who has lot&#x27;s of photos on a NAS, the Lychee app should not copy or delete the source file, it should only record the file path and insert it into DB. and then generate the required thumbnails. users who may have TB level photos, if copy again, it will be a lot of space waste and may encounter on performance problem.</p><p>Lychee should take <code>Synology Photo Station </code>or <code>Synology Moments</code> as a good example</p><p>如果要改进,应该怎么办?</p><p>其实都不用自己费脑子。Synology和QNAP这些专业的公司,拥有优秀的产品经理和项目经理,他们做出来的东西,经过了时间和用户的双重考验。 随便拿Synology的Photo Station参考一下吧。 群晖(Synology)提供免费的demo可以让你登录进去体验真正的群晖系统 -- DSM, 每次体验时间可长达30分钟。 分析一个相册的功能,足够了。</p><p>demo 体验地址: <a href="https://demo.synology.com/zh-cn">https://demo.synology.com/zh-cn</a></p><p>参考一下群晖的设计,<code>Lychee</code> 应该怎么做?</p><h2 id="相册功能重新设计"><a href="#相册功能重新设计" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>相册功能重新设计</h2><ol><li>相册名就是目录名,相册层级关系,就是目录层级关系。</li></ol><div><img alt="image" src="https://ttys3.dev/static/assets/syno-album-name.small-EOENTQ6H.png" width="310" height="400"/></div><div><img alt="image" src="https://ttys3.dev/static/assets/syno-album-name-is-dir-name.small-DV6T7TRY.png" width="528" height="400"/></div><ol start="2"><li>删除相册,就是删除目录及其下所有文件</li></ol><div><img alt="image" src="https://ttys3.dev/static/assets/syno-album-delete-is-dir-delete.small-NC2YLBPJ.png" width="643" height="400"/></div><ol start="3"><li>自动相册创建。当相册根目录下有新目录创建,并且有新文件添加时,新相册就自动创建了,相册名就是目录名。</li></ol><h2 id="导入功能重新设计"><a href="#导入功能重新设计" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>导入功能重新设计</h2><ol start="0"><li><p>用户选择相册,或直接使用当前位置的相册。</p></li><li><p>用户选择NAS上的图片源目录(实际上是经过dock volume映射过去的)</p></li><li><p>lychee扫描源目录所有图片</p></li><li><p>lychee将源目录图片入库,并生成中图和小图. 源图片路径保持不变,lychee只记录源图片路径。</p></li></ol><p>中图和小图统一放在lychee的.lychee_thumb 目录下, 缩略图路径与源目录路径保持映射关系, 也就是说,不依赖数据库,根本源文件路径,可以计算出缩略图的路径。</p><h2 id="上传功能重新设计"><a href="#上传功能重新设计" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>上传功能重新设计</h2><ol start="0"><li><p>用户选择相册,或直接使用当前位置的相册。</p></li><li><p>用户选并上传本地电脑的图片到lychee</p></li><li><p>lychee将源目录图片入库,并生成中图和小图. 源图片路径为相册所在的目录,文件名不应该被修改成随机字符,因为随机字符意味了这个文件离开了这个系统,连鬼都不知道这个文件是干嘛的。 中图和小图统一放在lychee的.lychee_thumb 目录下, 缩略图路径与源路径保持映射关系。</p></li></ol><p>当然,以上,只是一些思考罢了。一个人的精力是有限的,哪里有这么多时间来做?</p> Tue, 12 May 2020 18:24:53 GMT ttyS3 https://ttys3.dev/blog/how-to-build-your-first-vscode-extension 如何编写你的第一个vscode插件 https://ttys3.dev/blog/how-to-build-your-first-vscode-extension <h2 id="准备工作"><a href="#准备工作" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>准备工作</h2><ol><li><p>安装好最新版本的vscode(这个自动不用说),但是我这里要强调一下的是,vscode插件用vscode自己来写,能省很多事情,虽然你也可以用WebStorm之类的来写</p></li><li><p>安装好基本的工具,Git和Node.js(包含我们需要的npm)</p></li><li><p>安装<a href="http://yeoman.io/">Yeoman</a>和<a href="https://www.npmjs.com/package/generator-code">VS Code Extension Generator</a></p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token function">npm</span> <span class="token function">install</span> <span class="token variable parameter">-g</span> yo generator-code </span></code></pre></div></li></ol><p>Yeoman号称“现代webapps脚手架工具”,使用它可以非常方便地生成各种项目的代码,而不是每个字节都要你从0撸起。 你需要生成的那个项目的“模板”,在Yeoman里被称为“生成器&quot;(generator), 这为是为什么我们安装了Yeoman之后, 还要安装<strong>VS Code Extension Generator</strong> (就是我们命令行中的<code>generator-code</code>, 这里的<code>code</code>不是代码的意思,则是指<code>vscode</code>) 在Yeoman的官网你可以找到上千个生成器: <a href="https://yeoman.io/generators/">https://yeoman.io/generators/</a></p><h2 id="第一个vscode插件"><a href="#第一个vscode插件" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>第一个vscode插件</h2><h3 id="代码生成"><a href="#代码生成" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>代码生成</h3><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">❯ yo code </span><span class="code-line"> </span><span class="code-line"> _-----_ ╭──────────────────────────╮ </span><span class="code-line"> <span class="token operator">|</span> <span class="token operator">|</span> │ Welcome to the Visual │ </span><span class="code-line"> <span class="token operator">|</span>--<span class="token punctuation">(</span>o<span class="token punctuation">)</span>--<span class="token operator">|</span> │ Studio Code Extension │ </span><span class="code-line"> <span class="token variable"><span class="token variable">`</span>---------´ │ generator<span class="token operator">!</span> │ </span></span><span class="code-line"><span class="token variable"> <span class="token punctuation">(</span> _´U<span class="token variable">`</span></span>_ <span class="token punctuation">)</span> ╰──────────────────────────╯ </span><span class="code-line"> /___A___<span class="token punctuation">\</span> / </span><span class="code-line"> <span class="token operator">|</span> ~ <span class="token operator">|</span> </span><span class="code-line"> __<span class="token string">&#x27;.___.&#x27;</span>__ </span><span class="code-line"> ´ <span class="token variable"><span class="token variable">`</span> <span class="token operator">|</span>° ´ Y <span class="token variable">`</span></span> </span><span class="code-line"> </span><span class="code-line">? What <span class="token class-name builtin">type</span> of extension <span class="token keyword">do</span> you want to create? <span class="token punctuation">(</span>Use arrow keys<span class="token punctuation">)</span> </span><span class="code-line">❯ New Extension <span class="token punctuation">(</span>TypeScript<span class="token punctuation">)</span> </span><span class="code-line"> New Extension <span class="token punctuation">(</span>JavaScript<span class="token punctuation">)</span> </span><span class="code-line"> New Color Theme </span><span class="code-line"> New Language Support </span><span class="code-line"> New Code Snippets </span><span class="code-line"> New Keymap </span><span class="code-line"> New Extension Pack </span><span class="code-line"><span class="token punctuation">(</span>Move up and down to reveal <span class="token function">more</span> choices<span class="token punctuation">)</span> </span></code></pre></div><p>不得不说这个生成器真是方便和强大。既然我们是要生成扩展,当然是选”New Extension“了,那么这个选项分两种语言可选:TypeScript 和 JavaScript.</p><p>虽然老灯更熟悉JavaScript, 但是,这里老灯要选择的是TypeScript,后面会为解释为什么。</p><p>然后这个yo还会问你一些问题:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">? What<span class="token string">&#x27;s the name of your extension? wudeng </span></span><span class="code-line"><span class="token string">? What&#x27;</span>s the identifier of your extension? wudeng </span><span class="code-line">? What&#x27;s the description of your extension? this is a demo extension <span class="token keyword">for</span> fun </span><span class="code-line">? Initialize a <span class="token function">git</span> repository? Yes </span><span class="code-line">? Which package manager to use? <span class="token function">npm</span> </span></code></pre></div><p>插件名称,这里由于我们只是创建一个演示插件,起名比较随意,就叫<code>wudeng</code>(无灯)吧。 然后它会问你identifier(标识),默认和名字一样就OK,嗯,直接回车。 <code>identifier</code>一般会用来组成插件在vscode插件市场的URL,也会用于插件安装时的快速安装命令。 因此,一般是使用纯小写英文。 然后description是简短地描述一下,你这个插件是干嘛的。 接着会问你是不是要初始化git仓库,当然是<code>yes</code>. 最后问你是用哪个包管理器,npm 或 yarn, 老灯这里就直接使用npm了(2020年了,npm不再比yarn慢多少了).</p><div><img alt="yo-code-gen-2020-05-04-18-58-05.png" src="https://ttys3.dev/static/assets/yo-code-gen-2020-05-04-18-58-05-25OEDJAG.png" width="2610" height="1776"/></div><h3 id="运行调试"><a href="#运行调试" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>运行调试</h3><p>我们直接用vscode打开刚才生成的那个目录(<code>wudeng</code>), 为了方便区, 我们把此时打开的vscode窗口叫做”代码编辑窗口“,然后,神奇的操作来了! 直接按<code>F5</code>,没错,就是<code>F5</code>, vscode会开始自动构建插件代码,然后自动启动了另一个vscode窗口。 这个窗口有点特别,它不是普通的窗口,而是加载了我们当前打开的插件的窗口。</p><p>窗口的标题有vscode自动加的前缀 <code>Extension Development Host] - </code>, 为了方便区别,我们把此vscode窗口叫做”扩展开发宿主窗口“。</p><div><img alt="vscode-dev-host-2020-05-04-19-10-10.png" src="https://ttys3.dev/static/assets/vscode-dev-host-2020-05-04-19-10-10-RSUKEEUV.png" width="810" height="124"/></div><p>然后,我们在新开的”扩展开发宿主窗口“中,在命令面板(Ctrl+Shift+P)中输入Hello World命令。</p><div><img alt="vscode-dev-hello-world-2020-05-04-19-12-12.png" src="https://ttys3.dev/static/assets/vscode-dev-hello-world-2020-05-04-19-12-12-F5SZ5KOT.png" width="678" height="298"/></div><p>按回车之后,vscode右下角弹出提示信息:</p><div><img alt="vscode-hello-msg-2020-05-04-19-12-51.png" src="https://ttys3.dev/static/assets/vscode-hello-msg-2020-05-04-19-12-51-Z7BICCTC.png" width="982" height="302"/></div><p>接下来,我们看下,即使是这么简单的东西,它是如何实现的。</p><p>在”代码编辑窗口“,我们双击打开<code>src/extension.ts</code>这个源码文件。 可以看到它注册(registerCommand)了一个标识为<code>wudeng.helloWorld</code>的命令(command), 这个命令的处理函数非常简单,就是一个箭头函数,功能就是显示一条提示信息(<code>showInformationMessage</code>), 信息内容为 <code>Hello World from wudeng!</code></p><div class="relative"><pre><code class="code-highlight language-typescript"><span class="code-line"><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span>window<span class="token punctuation">.</span><span class="token function">showInformationMessage</span><span class="token punctuation">(</span><span class="token string">&#x27;Hello World from wudeng!&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>我们把文字内容修改成 <code>Hello World from 也无荒野也无灯!</code>会如何? 重新在”扩展开发宿主窗口“中执行Hello World命令,发现,执行结果并没有改变。 因为,插件并没有重新加载。我们更新了代码,vscode自动重新编译生成了新的插件代码,但是”扩展开发宿主窗口“ 没有重新加载新生成的代码。 要让插件代码重新加载也很简单,我们切到”代码编辑窗口“,点击顶部的绿色<code>Restart</code>按钮(或者按快捷键<code>Ctrl+Shift+F5</code>)</p><div><img alt="vscode-dev-toolbar-2020-05-04-19-24-20.png" src="https://ttys3.dev/static/assets/vscode-dev-toolbar-2020-05-04-19-24-20-TFCTDA4H.png" width="774" height="208"/></div><p>然后”扩展开发宿主窗口“就会自动重新加载新的插件代码。</p><div><img alt="vscode-hello-mod-msg-2020-05-04-19-25-43.png" src="https://ttys3.dev/static/assets/vscode-hello-mod-msg-2020-05-04-19-25-43-6MGBPOIV.png" width="938" height="184"/></div><p>tips:</p><blockquote><p>除了在”代码编辑窗口“,点击顶部的绿色<code>Restart</code>按钮(或者按快捷键<code>Ctrl+Shift+F5</code>), 还可以”扩展开发宿主窗口“中,按<code>Ctrl+Shift+i</code>打开调试控制台,然后把光标定位到调试控制台, 再按<code>F5</code>即可重载插件。</p></blockquote><h2 id="小试牛刀"><a href="#小试牛刀" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>小试牛刀</h2><p>当然,发个hello world确实显得这个文章没有太多意义了。你这个hello world插件又不能实际工作。 所以,发hello world当然不是老灯的本意了。hello world满大街都能找到。 文章的重点部分,当然是在这后面部分了。</p><h3 id="缘由"><a href="#缘由" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>缘由</h3><p>其实在此之前老灯一直不会写vscode插件。也没有想过要写vscode插件,只到有一天,老灯开始用Hugo写博客,发现某个Hugo插件一直用起来不爽, 于是就想,能不能想办法改一改。我主要用它的<code>New Post</code>功能来创建新的日志markdown文件。 为什么不直接新建markdown文件,然后再写日志?因为Hugo的markdown文件不是普通的markdown文件,它在文件最开始会有一些<a href="https://gohugo.io/content-management/front-matter/">Front Matter</a>, 而通过Hugofy的<code>New Post</code>,它实际上是调用的hugo new post/xxx/xxx.md来创建新日志,因此会自动生成<code>Front Matter</code>.</p><div><img alt="hugo-new-front-matter-2020-05-04-19-45.gif" src="https://ttys3.dev/static/assets/hugo-new-front-matter-2020-05-04-19-45-DNNADBLU.gif" width="800" height="299"/></div><p>这个<code>New Post</code>操作本身没有问题。 但是它对于“右击某个目录,然后在这个目录下创建日志”这种简单地需求都无法满足。 看上去它的命令行方式的<code>New Post</code>操作是OK,但是,试想一下非常常见的需求: 在Hugo我们习惯用文件夹的方式来组织日志,默认情况下,目录就是分类,假设我有一个linux父分类, 然后其下有Fedora, ArchLinux, Debian等子分类,按照这个Hugofy的命令,我们要输入的文件名为 <code>linux/fedora/日志标题.md</code>,而如果插件有这种支持,我们就可以直接在<code>fedora</code>目录上右击,然后选择新建日志。</p><p>因此,我做的第一个修改,就是增加右键菜单的支持。 其次还有一些bug, 比如下载Hugo主题的功能不能正常工作, Hugo有错误这个插件完全没提示是什么错误,然后你会一头雾水不知道怎么解决。 错误提示信息不够友好和准确等等。下面会一一详细说明,并试图操刀解决。</p><h3 id="第一刀-优化新建日志和page-bundle支持"><a href="#第一刀-优化新建日志和page-bundle支持" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>第一刀: 优化新建日志和page bundle支持</h3><p>我们先来做第一步吧,把源码fork到自己的仓库: <a href="https://github.com/ttys3/hugofy-vscode">https://github.com/ttys3/hugofy-vscode</a></p><p>然后clone到本地,用vscode打开,然后执行F5,发现并没有像预期的那样,打开一个新的<code>Extension Development Host] - </code>窗口。 而是弹出了一个popup,让你选是C++还是Node.js等,然后我想,既然是Node.js的项目,就选Node.js吧,然而结果还是不能运行。 然后查看了下vscode console的日志,发现是提示找不到<code>vscode</code>这个module, 明明在<code>package.js</code>里已经加了这个module的,为什么运行的时候还提示找不到呢?</p><p>我用meld这个对比工具,把hugofy-vscode的目录跟我们的hello world扩展目录进行了对比,发现hugofy-vscode的目录下缺少一些vscode需要的文件。 总体来说,整个<code>.vscode</code>这个目录是缺失的。直接把hello world下面的<code>.vscode</code>目录复制过去,发现F5功能神奇地可以工作了。</p><p>然后大概浏览了一下代码,发现这些代码没有严格遵守typescript的写法。 于是编辑 <code>tsconfig.json</code> 启用严格类检测: <code>&quot;strict&quot;: true /* enable all strict type-checking options */</code></p><p>代码里充斥着各种分号<code>;</code>, 自从用习惯了Golang之后,我再也不习惯写带分号的语句了。 那么,Typescript本身是不是支持和提倡无分号语句呢,于是我进行了一翻搜索。</p><blockquote><p>TypeScript follows the same ASI rules as JavaScript. Semicolons are technically not required in either language, save for a few rare, specific cases.</p></blockquote><p>见 <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#semicolon-formatter-option">https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#semicolon-formatter-option</a></p><p><a href="https://stackoverflow.com/questions/51004223/are-semicolons-necessary-in-typescript-2/51004311#51004311">https://stackoverflow.com/questions/51004223/are-semicolons-necessary-in-typescript-2/51004311#51004311</a></p><p><a href="https://medium.com/@eugenkiss/dont-use-semicolons-in-typescript-474ccfe4bdb3">https://medium.com/@eugenkiss/dont-use-semicolons-in-typescript-474ccfe4bdb3</a></p><p>既然ts像js一样遵循ASI规则,那我们就可以放心地省略分号了。</p><p>编辑 .eslintrc.json 禁用分号:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">&quot;@typescript-eslint/semi&quot;: &quot;never&quot;, </span><span class="code-line">&quot;semi&quot;: &quot;off&quot; </span></code></pre></div><p>然后,咱也没写过ts这玩意啊。倒底靠不靠谱呢?</p><p>咱也没太多时间看官方手册来学个ts, 像吃快餐一样的快速上手教程最适合,我们就要看两下就开搞的那种,嗯,找到一个不错的上手教程 <a href="https://ts.xcatliu.com/">https://ts.xcatliu.com/</a></p><p>老灯花了几分钟大概了解了一下ts这个语言。</p><p>然后,开始撸vscode插件了,先拿Hugofy这个插件开刀。</p><p>根据vscode文档 <a href="https://code.visualstudio.com/api/references/contribution-points">https://code.visualstudio.com/api/references/contribution-points</a> ,我们要增加右键菜单,需要修改<code>package.json</code>的<code>contributes</code>字段. (你不是第一次搞vscode插件么,你怎么知道这些的?当然是通过搜索找到了文档)</p><p>我们在<code>contributes</code>字段下增加key<code>menus</code>,其值为一对象:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;explorer/context&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;when&quot;</span><span class="token operator">:</span> <span class="token string">&quot;explorerResourceIsFolder&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.newPost&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;group&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugo&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">]</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p><code>when</code>表示,只有在exploer, 也就是vscode左边的文件浏览器,才会触发这个右键菜单。并且,我们的需求是,只要求对目录右击时能有右键菜单。 因为这个<code>when</code>的条件是explorerResourceIsFolder的值为<code>true</code>的时候。 command 为要执行的命令,这个命令是我们在插件初始化时注册的。 对于一个第一次撸vscode插件的人来说,要知道这一点显然是不容易的,因此,我这个资源是从so上面搜索到的 <a href="https://stackoverflow.com/questions/38267360/vscode-extension-api-identify-file-or-folder-click-in-explorer-context-menu">https://stackoverflow.com/questions/38267360/vscode-extension-api-identify-file-or-folder-click-in-explorer-context-menu</a></p><p>这个答案中还提到了插件开发中一个非常重要的技能,调用<code>Developer: Inspect Context Keys</code>来获取这些信息。</p><div><img alt="vscode-dev-inspect-ctx-keys-2020-05-04-22-51-27.png" src="https://ttys3.dev/static/assets/vscode-dev-inspect-ctx-keys-2020-05-04-22-51-27-MD2HUFRS.png" width="904" height="1016"/></div><p>注意要打开控制台(Ctrl+Shift+i), 不然你是看不到结果的。但是我上面那个图还是不能太直观的描述这个inspect操作,因此老灯又做了个gif动图:</p><div><img alt="vscode-dev-ctx-inspect.gif" src="https://ttys3.dev/static/assets/vscode-dev-ctx-inspect-3STGNWAF.gif" width="800" height="630"/></div><p>好了,现在我们测试一下右键菜单,是不是出来了?</p><div><img alt="right-click-ctx-menu-new-post-test-2020-05-04-23-20.gif" src="https://ttys3.dev/static/assets/right-click-ctx-menu-new-post-test-2020-05-04-23-20-52LTUUS7.gif" width="800" height="724"/></div><p>右键菜单是出来了,但是执行的命令呢? 原代码是不能处理右键菜单的,因此我们要引入一个参数。右击了哪个对象,这个对象必须传入到我们的命令里。 通过一次调试,我们可以发现,我们需要的被右击的目录的路径,就在对象的 <code>fsPath</code>这个属性里。但是如果是直接执行的命令(非右击的情况),命令处理函数 是收不到任何对象的,此时它是<code>undefined</code>, 因此我们修改后的newPost()函数必须要同时支持这两种情况。</p><p>另外一点是,由于我们主要是采用Hugo的<a href="https://gohugo.io/content-management/page-bundles/">page bundle</a>的方式来组织日志及其资源(图片,视频等), 因此,markdown文件的默认名称就是<code>index.md</code>,我们需要快速的创建日志文件,而不需要用户再次手动输入<code>index.md</code>这些字符串,这样太麻烦了。 查询vscode api文档,得知<code>showInputBox</code>是可以有默认值的,这个值放在<code>value</code>属性里,就像这样:</p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line">vscode<span class="token punctuation">.</span><span class="token property-access">window</span><span class="token punctuation">.</span><span class="token property-access function method">showInputBox</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property literal-property">placeHolder</span><span class="token operator">:</span> <span class="token string">&#x27;Enter filename&#x27;</span><span class="token punctuation">,</span> <span class="token property literal-property">value</span><span class="token operator">:</span> <span class="token string">&#x27;index.md&#x27;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span></code></pre></div><p>好了,命令处理函数修改好了。如果我们输入中文的路径呢?中文路径在URL显示的时候非常不友好,会被转码为urlencode之后的形式。 因此,我们要么手动在Hugo markdown文件里的Front matter里加一个<code>slug</code>字符,手写上英文版的<code>slug</code>, 要么,还有更自动的方式? 没错,我们可以修改代码,让它自动完成中文到拼音的转换。当我们输入<code>测试中文</code>时,新建时目录名自动转换为拼音的<code>ce-shi-zhong-wen</code>.</p><p>我们再来看下修改后的效果:</p><div><img alt="chinese-slug-auto-convert-test-2020-05-04-23-33.gif" src="https://ttys3.dev/static/assets/chinese-slug-auto-convert-test-2020-05-04-23-33-4XSB5N3W.gif" width="800" height="430"/></div><p>这里,文件名相对于<code>content/post</code>的路径是<code>linux/archlinux/ce-shi-zhong-wen/index.md</code>, 如果我们使用原来的插件而不是我们修改过后的, 要输入这么长的路径,是不是很麻烦?而经过修改后的插件,我们只需要在<code>archlinux</code>目录上右击,然后输入<code>测试中文</code>,后面的<code>index.md</code>插件已经预先写好了, 所以,在写<a href="https://gohugo.io/content-management/page-bundles/">page bundle</a>或分类路径比较深的情况下,这次修改带来了非常大的方便。</p><h3 id="第二刀-修复主题下载"><a href="#第二刀-修复主题下载" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>第二刀: 修复主题下载</h3><h4 id="修复请求问题"><a href="#修复请求问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>修复请求问题</h4><p>原来的代码主题下载不工作,我们先分析下为什么。通过一些简单的<code>console.log</code>日志打印,我们很快就能发现,原来的插件代码调用的是<code>https.get</code>来请求github api. 但是github的api进行了一些重定向操作,而<code>https.get</code>是不支持重定向的,怎么办?我们换一个更重量级的库来请求https? 好像没有必要。 <code>https.get</code>非常轻量级且能完成工作,我们需要的只是让它能处理http重定向而已。又是一番搜索,很快,找到一个名为<a href="https://www.npmjs.com/package/follow-redirects">follow-redirects</a>库,正是为解决重定向问题而生的。 我们只需要把原来的import代码换成<code>import { https } from &#x27;follow-redirects&#x27;</code>, 然后实际的代码都不用动,就解决这个问题了。 另外要记得安装一个这个库:<code>npm i follow-redirects</code></p><h4 id="修复逻辑问题"><a href="#修复逻辑问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>修复逻辑问题</h4><p>很多时候,一个主题对于它自己的名称(主要会用于URL路径加载资源文件)是有要求的。 所以我们不能直接github的仓库名称是什么,我们把主题git clone下来就存到什么目录,这会导致问题。</p><p>现在的问题是,Hugo的主题仓库里,很多仓库名称命名并不统一。有些是<code>hugo-xxx-theme</code>的格式的名称,真正的主题名就是中间的<code>xxx</code>, 有些是<code>hugo-theme-xxx</code>,最后的<code>xxx</code>才是真正的主题名称。还有各式各样的,比如<code>xxx-hugo-theme</code>,<code>hugo-xxx</code>,<code>xxx-hugo</code>, <code>theme-xxx</code>和<code>xxx-theme</code>等。 还有一些更过分的, 比如<code>xxx-hugo-yyy-theme</code> 之类的。这种程序没法自动处理,因为真正的主题名,有可能是xxx, 也有可能是yyy.</p><p>总之,我们在处理主题名称的时候,要进行<strong>规范化</strong>处理,提取出真正的主题名。当然,这种处理是要尽可能是避免的,最好的解决办法是,Hugo官方出面,规范化主题repo的命名, 不规则的主题,要重新命名后再加入官方repo.对于一个已经存在300个以上主题的仓库来说,要这样办是非常困难的,因为重新命名主题,可能会破坏现存用户的主题更新操作。</p><p>还有一点是,当用户切换主题时,如果Hugo server已经启动了,则我们需要重启Hugo server以应用新的主题。</p><h4 id="优化请求"><a href="#优化请求" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>优化请求</h4><p>原插件都是要进行二次请求,第一次请求用于从<code>gohugoio/hugoThemes</code>这个仓库获取所有主题列表,第二次请求根据用户选择了哪个主题,再请求一次api获取这个主题的git clone URL. 但是我们仔细观察,会发现<code>gohugoio/hugoThemes</code>这个仓库有些特殊,它里面的主题,都是采用git submodule的方式添加进来的,而不是添加的实际文件。 而我们观察第一次api请求获取主题列表时,里面有一个字段名为<code>html_url</code>, 这个值就像这样:<code>https://github.com/marketempower/axiom/tree/34156c0530092c3cef71bfeaa133c19673bb58b1&quot;</code> 眼尖的童鞋一眼就能看出,完全没有必要进行第二次请求,因为主题的仓库url就可以从这个<code>html_url</code>里提取出来,比如上面这个提取出来就是<code>https://github.com/marketempower/axiom.git</code> 然后也有极个别主题<code>html_url</code>字段值为null的,这是为什么呢?原来这几个主题的源git仓库不是github, 而是在其它git仓库托管服务商那里,比如在gitlab之类的。数了一下,发现这种类型的仓库数量只在个位数。因此我们可以优化代码,使这个代码在90%以上的情况,都不需要进行第二次api请求就能直接知道主题的git URL.</p><p>第二点优化就是,原代码是每次在执行下载主题的命令时才开始下载主题列表,而这个获取过程,在国外可能会很快,但是国内的情况大家也都明白,耗时是比较长的。这就导致了,你点击下载主题的命令,但是过了好长时间才会有结果出来。所以,我们可以在插件初始化时就在后台下载好主题列表,然后,我们引入一个缓存机制,后续任何时候要下载主题,都不需要进行第二次API请求来获取主题列表。 通过查询vscode api文档,我们知道,插件初始化时会调用 <code>activate</code>, 那么我们就在<code>activate</code>处理函数里加上这个主题获取的动作。</p><div class="relative"><pre><code class="code-highlight language-javascript"><span class="code-line"><span class="token comment">//文件顶部加上声明</span> </span><span class="code-line"><span class="token keyword">let</span> <span class="token property literal-property">extCache</span><span class="token operator">:</span> any </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">const</span> themelistCacheKey <span class="token operator">=</span> <span class="token string">&#x27;ttys3.hugoy.themeList&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// Extension activation method</span> </span><span class="code-line"><span class="token keyword">const</span> <span class="token function function-variable">activate</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token property literal-property">context</span><span class="token operator">:</span> any</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token comment">// 插件加载,初始化缓存对象</span> </span><span class="code-line"> extCache <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">vscache</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token comment">// 注册插件命令</span> </span><span class="code-line"> context<span class="token punctuation">.</span><span class="token property-access">subscriptions</span><span class="token punctuation">.</span><span class="token property-access function method">push</span><span class="token punctuation">(</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span><span class="token property-access">commands</span><span class="token punctuation">.</span><span class="token property-access function method">registerCommand</span><span class="token punctuation">(</span><span class="token string">&#x27;hugofy.getVersion&#x27;</span><span class="token punctuation">,</span> getVersion<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span><span class="token property-access">commands</span><span class="token punctuation">.</span><span class="token property-access function method">registerCommand</span><span class="token punctuation">(</span><span class="token string">&#x27;hugofy.newSite&#x27;</span><span class="token punctuation">,</span> newSite<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span><span class="token property-access">commands</span><span class="token punctuation">.</span><span class="token property-access function method">registerCommand</span><span class="token punctuation">(</span><span class="token string">&#x27;hugofy.newPost&#x27;</span><span class="token punctuation">,</span> newPost<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span><span class="token property-access">commands</span><span class="token punctuation">.</span><span class="token property-access function method">registerCommand</span><span class="token punctuation">(</span><span class="token string">&#x27;hugofy.build&#x27;</span><span class="token punctuation">,</span> build<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span><span class="token property-access">commands</span><span class="token punctuation">.</span><span class="token property-access function method">registerCommand</span><span class="token punctuation">(</span><span class="token string">&#x27;hugofy.downloadTheme&#x27;</span><span class="token punctuation">,</span> downloadTheme<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span><span class="token property-access">commands</span><span class="token punctuation">.</span><span class="token property-access function method">registerCommand</span><span class="token punctuation">(</span><span class="token string">&#x27;hugofy.setTheme&#x27;</span><span class="token punctuation">,</span> setTheme<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span><span class="token property-access">commands</span><span class="token punctuation">.</span><span class="token property-access function method">registerCommand</span><span class="token punctuation">(</span><span class="token string">&#x27;hugofy.startServer&#x27;</span><span class="token punctuation">,</span> startServer<span class="token punctuation">)</span><span class="token punctuation">,</span> </span><span class="code-line"> vscode<span class="token punctuation">.</span><span class="token property-access">commands</span><span class="token punctuation">.</span><span class="token property-access function method">registerCommand</span><span class="token punctuation">(</span><span class="token string">&#x27;hugofy.stopServer&#x27;</span><span class="token punctuation">,</span> stopServer<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">)</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">//获取Hugo主题列表并缓存</span> </span><span class="code-line"> themeUtils<span class="token punctuation">.</span><span class="token property-access function method">getThemesList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token property-access function method">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token property literal-property">themeList</span><span class="token operator">:</span> any</span><span class="token punctuation">)</span> <span class="token operator arrow">=&gt;</span> <span class="token punctuation">{</span> </span><span class="code-line"> extCache<span class="token punctuation">.</span><span class="token property-access function method">put</span><span class="token punctuation">(</span>themelistCacheKey<span class="token punctuation">,</span> themeList<span class="token punctuation">)</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line">exports<span class="token punctuation">.</span><span class="token property-access">activate</span> <span class="token operator">=</span> activate </span></code></pre></div><h4 id="优化主题选择列表"><a href="#优化主题选择列表" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>优化主题选择列表</h4><p>由于Hugo官方主题git仓库是使用的submodule, 虽然我们可以一个请求获取绝大多数主题的git URL, 但是对于这个主题的star数量,还是获取不到的。 如果要一次性给300个主题来一个star数据获取,通过REST API也会导致请求过于频繁。有没有办法解决呢? 办法当然是有的,GitHub GraphQL API可以一次请求和返回多个资源,但是不同于REST API可以有限地公开请求(不需要登录),GitHub GraphQL API是需要有密钥才能请求的。 直接使用,当然会给使用者造成一定的麻烦,毕竟人家只是需要安装个插件,然后还要提供一个github 密钥,有点麻烦了。因此,这种可以做成可选方案。 如果提供了Github API密钥,就可以显示更详细的信息(fork数量,star数量,最近更新代码时间等,然后可以根据star排序等等)。否则,就显示名称 + URL.</p><p>使用GitHub GraphQL API是可行的,我们可以随便一次请求3个主题的fork数量,star数量,创建时间,最后提交代码的时间:</p><div><img alt="github-graphql-hugo-themelist-2020-05-05-01-24-50.png" src="https://ttys3.dev/static/assets/github-graphql-hugo-themelist-2020-05-05-01-24-50-FQZYD6UA.png" width="2292" height="1250"/></div><p>当然,这里老灯时间有限,就不实现这个功能了,或许在看文章的你有时间,可以尝试实现,来提交PR.</p><h3 id="第三刀-其它改进"><a href="#第三刀-其它改进" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>第三刀: 其它改进</h3><h4 id="优化错误提示和处理"><a href="#优化错误提示和处理" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>优化错误提示和处理</h4><p>当Hugo server启动失败的时候,大部分是由于主题缺少必要的配置(有些主题会需要一些特别配置),或者,这个主题本身的代码存在问题。 原插件显示的是错误的Hugo命令不存在这种”错误的错误信息“。我们修改之后,让它显示详细的失败错误信息,以方便用户修正主题配置,顺利应用新主题。</p><div><img alt="detailed-error-message-2020-05-05-01-41.gif" src="https://ttys3.dev/static/assets/detailed-error-message-2020-05-05-01-41-D22CHLNL.gif" width="800" height="558"/></div><p>提示信息优化方面也有很多工作可以做,比如,当用户点击下载一个主题时,很可能由于网络原因下载失败,此时,应该友好地显示一个“重新下载”的按钮,而不是重新返回主题列表, 再让用户肉眼找到之前他想下载的那个主题。 当一个主题下载成功的时候,用户很可能是想尝试一下使用这个主题的,插件不应该傻傻地只完成主题下载。而是应该提供一个“使用当前主题“的按钮,用户点击后即可应用当前主题, 并自动打开预览页面。</p><p>优化后的效果,选择下载主题时,主题列表可以瞬间显示, 另外,下载成功时会有”应用此主题“和”启动服务器“的按钮:</p><div><img alt="hugo-quick-theme-list-and-down-succeed-actions-btn-2020-05-05-01-37.gif" src="https://ttys3.dev/static/assets/hugo-quick-theme-list-and-down-succeed-actions-btn-2020-05-05-01-37-VRAQXZAS.gif" width="800" height="558"/></div><p>这里可以讨论的地方有很多,甚至老灯当前发布的这个版本可能也有很多地方还可以优化的。</p><h4 id="增加默认快捷键"><a href="#增加默认快捷键" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>增加默认快捷键</h4><p>每次按<code>Ctrl+Shift+p</code>,然后再通过搜索关键字<code>hugo</code>来执行相应的命令,对于需要频繁执行的操作来说,会显得非常麻烦。如果有一个默认的快捷键映射,会更加方便。 这个插件有8个命令,所以在默认的快捷键映射上,也不可能占用8个快捷键,这样太浪费了。因此我这里使用第一组合键+<code>second key of chord</code>的方式。 比如,新建Post, 快捷键设置为<code>ctrl+shift+h p</code>,意思是,先按<code>ctrl+shift+h</code>然后释放,再按一下<code>p</code>然后释放,动作就触发了。设置主题(theme)的快捷键为 <code>ctrl+shift+h t</code>,这里的<code>h</code>取的是Hugo的意思,但是这里有个小问题,不过应该不会成为问题。vscode默认的快捷键里,<code>ctrl+shift+h</code>是有映射成<code>Search: Replace in Files</code>的。 但是由于vscode左侧快捷菜单就有搜索和替换的快捷按钮,因此,这个应该不会成为问题。如果实在是需要频繁的进行文件之间的替换操作,也可以自行设置快捷键。 插件只是提供默认地映射,用户可以自行修改。</p><p>有了快捷键,下载主题(d), 切换主题(t), 启动hugo服务器(s), 新建日志Post(p) 等等这些操作都非常顺畅了。而且键的字母默认是跟操作本身相关联的,基本上取的首字母,比较有意义, 从而记忆方面也不成问题。</p><p>根据vscode文档,我们需要向<code>package.json</code>文件<code>contributes</code>字段下增加如下快捷键配置:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token property">&quot;keybindings&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;key&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ctrl+shift+h s&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.startServer&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;key&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ctrl+shift+h b&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.build&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;key&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ctrl+shift+h d&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.downloadTheme&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;key&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ctrl+shift+h p&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.newPost&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;key&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ctrl+shift+h n&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.newSite&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;key&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ctrl+shift+h t&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.setTheme&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;key&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ctrl+shift+h x&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.stopServer&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;key&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ctrl+shift+h v&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;command&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy.getVersion&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">]</span> </span></code></pre></div><div><img alt="vscode-hugoy-keybindings-2020-05-05-03-07-01.png" src="https://ttys3.dev/static/assets/vscode-hugoy-keybindings-2020-05-05-03-07-01-3KLEFTZR.png" width="1538" height="1016"/></div><p>使用快捷键操作一下主题下载和主题切换:</p><div><img alt="download-switch-theme-2020-05-05-02-20.gif" src="https://ttys3.dev/static/assets/download-switch-theme-2020-05-05-02-20-XVKNZCUS.gif" width="800" height="527"/></div><h3 id="第四刀-webpack打包"><a href="#第四刀-webpack打包" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>第四刀: webpack打包</h3><p>webpack作为前端打包界的扛把子, 插件打包这种事自然少不了它。 事实上当你使用<code>vsce</code>命令发布插件时,vsce就会提示你,你的插件包含的文件数太多了,应该采用打包器打包一下。</p><p>但是这里,我们面对的是一个现存的插件,它在创建之初就没有使用webpack. 因此我们要给它加上webpack打包。</p><p>打包这部分主要是参考 <a href="https://code.visualstudio.com/api/working-with-extensions/bundling-extension">https://code.visualstudio.com/api/working-with-extensions/bundling-extension</a></p><p>以及这个文档中提到的参考PR <a href="https://github.com/Microsoft/vscode-references-view/pull/50">https://github.com/Microsoft/vscode-references-view/pull/50</a></p><p>如果把代码贴出来就太长了,所以这里我说一下commit: <a href="https://github.com/ttys3/hugofy-vscode/commit/aa848221624ce13a52985568f2eeb19bd5d3ec28">https://github.com/ttys3/hugofy-vscode/commit/aa848221624ce13a52985568f2eeb19bd5d3ec28</a></p><p>注意:</p><blockquote><p>由于<code>tasks.json</code>中的<code>problemMatcher</code>换成了<code>$ts-webpack</code>,而vscode默认并不支持这个, 因此我要要安装一个额外的插件<a href="https://marketplace.visualstudio.com/items?itemName=eamodio.tsl-problem-matcher">TypeScript + Webpack Problem Matchers</a>. 在vscode中,打开Quick Open (Ctrl+P),执行 <code>ext install eamodio.tsl-problem-matcher</code> 即可快速安装。</p></blockquote><h2 id="如何发布插件"><a href="#如何发布插件" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何发布插件</h2><p>此部分基本上参考 <a href="https://code.visualstudio.com/api/working-with-extensions/publishing-extension">https://code.visualstudio.com/api/working-with-extensions/publishing-extension</a></p><p>vscode采用<code>vsce</code>(Visual Studio Code Extensions的缩写)命令进行插件的打包,发布和管理。 如果没有安装,首先我们要安装一下这个工具:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token function">npm</span> <span class="token function">install</span> <span class="token variable parameter">-g</span> vsce </span></code></pre></div><p>发布插件时需要PAT(Personal Access Token的缩写), 这个PAT怎么获取呢?</p><p>首先,你要有一个Azure DevOps organization,如果没有Azure账号,你要注册一个。 登录Azure账号后,进入 <a href="https://dev.azure.com/">https://dev.azure.com/</a> 会进入你的组织主页。</p><p>比如老灯的组织名是<code>wudeng</code>, 那么进入的是<code>https://dev.azure.com/wudeng/</code>,进入这里之后,啥项目也不用创建。 咱不用管其它的,只需要点击带齿轮的小人图标,进去之后点击<code>+New Token</code>创建新的PAT。</p><div><img alt="azure-devops-PAT-menu-2020-05-05-02-42.gif" src="https://ttys3.dev/static/assets/azure-devops-PAT-menu-2020-05-05-02-42-VJS2FTYH.gif" width="800" height="824"/></div><p>这里要注意的是, Organization 一定要选 <code>All accessible organizations</code>,不然你后面会遇到<code>ERROR Failed request: (401)</code>错误。 权限范围那里,找到<code>Marketplace</code>, 并勾选上 <code>Acquire</code> 和 <code>Manage</code>:</p><div><img alt="azure-pat-form-2020-05-05-02-45-50.png" src="https://ttys3.dev/static/assets/azure-pat-form-2020-05-05-02-45-50-TEP7R4VQ.png" width="1284" height="1744"/></div><p>创建好PAT后一定要记得复制保存好,因为后面不会再显示了。</p><p>OK, 有了PAT,我们可以开始创建 publisher 了:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">vsce create-publisher ttys3 </span></code></pre></div><p>publisher 是对于插件开发者的标识, 这个标识是唯一的,老灯这里就用<code>ttys3</code>吧。</p><p>根据 <a href="https://code.visualstudio.com/api/references/extension-manifest">https://code.visualstudio.com/api/references/extension-manifest</a> , 我们需要在<code>package.json</code>中增加<code>publisher</code>,这个值就是我们刚才创建的。</p><p>另外还有一些字段比较重要:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;hugofy&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;publisher&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ttys3&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;repository&quot;</span><span class="token operator">:</span> <span class="token string">&quot;https://github.com/ttys3/hugofy-vscode&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;version&quot;</span><span class="token operator">:</span> <span class="token string">&quot;0.3.3&quot;</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>插件的唯一标识是由<code>publisher</code>.<code>name</code>组成的,因此要选用好的方便记忆和搜索的名字。 <code>repository</code>是源码仓库,这个方便大家点击和查看源码。 <code>version</code>是版本号</p><p>发布插件:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token class-name builtin">cd</span> 插件所在目录 </span><span class="code-line">vsce publish 要发布的版本号 </span></code></pre></div><p>比如 <code>vsce publish 0.3.3</code></p><p>发布成功后,新的版本不会马上出现,要等待几分钟后才可以看到。</p><p>发布之后就会得到一个插件页面,比如我这个是 <a href="https://marketplace.visualstudio.com/items?itemName=ttys3.hugofy">https://marketplace.visualstudio.com/items?itemName=ttys3.hugofy</a></p><div><img alt="vscode-market-ext-page-2020-05-05-02-57-25.png" src="https://ttys3.dev/static/assets/vscode-market-ext-page-2020-05-05-02-57-25-2IPW646A.png" width="2254" height="1678"/></div><h2 id="后记"><a href="#后记" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>后记</h2><p>由于篇幅关系,文章中不可能涉及太多代码,如果希望参与一起改进的朋友,可以直接查看仓库源码 <a href="http://github.com/ttys3/hugofy-vscode">http://github.com/ttys3/hugofy-vscode</a> 这也是老灯第一次使用ts写代码, 终究逃不过”真香定律“, Angular被ts拉拢了,Vue3直接采用ts编写了, 而React由于历史原因, 它比ts出来得早,因此它不可能是采用ts编写的,不过目前React<a href="https://create-react-app.dev/docs/adding-typescript/">也支持采用ts来编写代码</a>。</p><p>所以,老灯觉得,以ts目前这个势头,学一下还是有必要的。</p><h2 id="本文参考"><a href="#本文参考" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>本文参考</h2><p><a href="https://code.visualstudio.com/api/get-started/your-first-extension">https://code.visualstudio.com/api/get-started/your-first-extension</a></p><p><a href="https://liiked.github.io/VS-Code-Extension-Doc-ZH/">https://liiked.github.io/VS-Code-Extension-Doc-ZH/</a></p><p><a href="https://code.visualstudio.com/api/working-with-extensions/bundling-extension">https://code.visualstudio.com/api/working-with-extensions/bundling-extension</a></p><p><a href="https://code.visualstudio.com/api/working-with-extensions/publishing-extension#.vscodeignore">https://code.visualstudio.com/api/working-with-extensions/publishing-extension#.vscodeignore</a></p><p><a href="https://code.visualstudio.com/api/references/vscode-api">https://code.visualstudio.com/api/references/vscode-api</a></p><p><a href="https://code.visualstudio.com/api/references/contribution-points">https://code.visualstudio.com/api/references/contribution-points</a></p><p><a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#semicolon-formatter-option">https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#semicolon-formatter-option</a></p><p><a href="https://stackoverflow.com/questions/51004223/are-semicolons-necessary-in-typescript-2/51004311#51004311">https://stackoverflow.com/questions/51004223/are-semicolons-necessary-in-typescript-2/51004311#51004311</a></p><p><a href="https://medium.com/@eugenkiss/dont-use-semicolons-in-typescript-474ccfe4bdb3">https://medium.com/@eugenkiss/dont-use-semicolons-in-typescript-474ccfe4bdb3</a></p><p><a href="https://ts.xcatliu.com/basics/type-assertion">https://ts.xcatliu.com/basics/type-assertion</a></p><p><a href="https://github.com/microsoft/TypeScript/issues/27293">https://github.com/microsoft/TypeScript/issues/27293</a></p><p><a href="https://github.com/wmonk/create-react-app-typescript/issues/214">https://github.com/wmonk/create-react-app-typescript/issues/214</a></p><p><a href="https://scripter.co/hugo-leaf-and-branch-bundles/">https://scripter.co/hugo-leaf-and-branch-bundles/</a></p><p><a href="https://github.com/microsoft/vscode-extension-samples/blob/master/helloworld-sample/src/extension.ts">https://github.com/microsoft/vscode-extension-samples/blob/master/helloworld-sample/src/extension.ts</a></p><p><a href="https://stackoverflow.com/questions/39599514/vs-code-add-a-new-file-under-the-selected-working-directory/39599731#39599731">https://stackoverflow.com/questions/39599514/vs-code-add-a-new-file-under-the-selected-working-directory/39599731#39599731</a></p><p><a href="https://stackoverflow.com/questions/38267360/vscode-extension-api-identify-file-or-folder-click-in-explorer-context-menu">https://stackoverflow.com/questions/38267360/vscode-extension-api-identify-file-or-folder-click-in-explorer-context-menu</a></p> Mon, 04 May 2020 10:10:37 GMT ttyS3 vscodeextensionhowtohugo https://ttys3.dev/blog/nanodm-site-hosted-on-netlify 使用Hugo+Netlify 5分钟部署一个网站 -- NanoDM站点迁移到Netlify记 https://ttys3.dev/blog/nanodm-site-hosted-on-netlify <h2 id="前言"><a href="#前言" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>前言</h2><p>此前老灯介绍过最麻烦的Hugo站点部署方法,很多人可能光看配置文件就头疼了, 这次老灯借着给NanoDM站点迁移的机会,顺便介绍一下最简单的Hugo部署方法。</p><h2 id="为什么迁移"><a href="#为什么迁移" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>为什么迁移</h2><p>NanoDM当前的站点是基于Hugo静态站点生成器构建的。</p><h3 id="仓库为什么迁移到github"><a href="#仓库为什么迁移到github" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>仓库为什么迁移到github</h3><p>NanoDM的站点源码此前一直托管在我的bitbucket私人仓库,这次做的另一个改变是:迁移到github</p><p>新的仓库地址为: <a href="https://github.com/ttys3/nanodm.net">https://github.com/ttys3/nanodm.net</a> (欢迎fork, 欢迎贡献文章或编写FAQ)</p><p>迁移到github之后,可以方便大家一起维护NanoDM的文档。毕竟单靠我一人之力,精力非常有限。 大家平常使用的时候,总会遇到这样那样的问题,而这些问题有些在群里我看到后解答了,大部分时候忙去了没看群,我是没时间回复的。 如果整理成文档呢?那么不仅是群里的人可以看到,任何遇到困难的人都可以得到帮助。文档能形成记录,方便后续的查看和引用。 另一方面是,如果大家有使用心得需要分享的,或者解决了一个疑难问题希望能帮助后来者的,也可以通过github提交PR的方式来参与贡献文档, 合并通过后会直接显示在站点。</p><h3 id="为什么托管到netlify"><a href="#为什么托管到netlify" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>为什么托管到Netlify</h3><p>Hugo支持特别多的部署方式,比如大家常用的github pages(及其它git仓库托管服务商的类似pages服务), 无论是本地depoy静态文件到单独的github pages分支,还是采用github actions自动部署,我觉得,都没有使用Netlify部署方便。 因此,老灯这次偷个懒,直接用Netlify点几下鼠标完成了部署,更省事。</p><p>费用问题,对于一般的站点,Netlify的免费套餐完全够用。</p><p>此前一直托管在单独的服务器上,这次准备对服务器进行维护升级,为避免操作时影响访问,我决定将NanoDM站点托管到Netlify. 原NanoDM的服务器不再托管网站,只用于固件下载,demo站点演示等。</p><p>特此记录,一来方便老灯自己做备忘,二来大家想要”省事“的站点部署方案时,亦可参考本文。</p><h2 id="部署到netlify"><a href="#部署到netlify" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>部署到Netlify</h2><p>部署非常简单:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token key attr-name">github仓库用于托管Hugo文件</span> <span class="token punctuation">=</span><span class="token attr-value value">&gt; Netlify自动持续部署且托管网站</span> </span></code></pre></div><p>这哥俩都是托管,但是我们把他们合起来使用,他们配合得天衣无缝。</p><p>github仓库用于托管源码,一但你push了新提交到github的指定仓库,Netlify就会开始自动拉取代码并部署站点(自动执行Hugo命令生成静态站点并发布)。</p><p>那么Netlify怎么就知道你什么时候push了代码了呢?因为你在Netlify配置的时候,指定了仓库, 同时也把这个仓库的权限给予了Netlify在github的app,如下图:</p><p>进入仓库设置(Settings)页面,切到<code>Integrations</code>, 你就会发现这个仓库启用了一个名为<code>Netlify</code>的app:</p><div><img alt="github-repo-apps" src="https://ttys3.dev/static/assets/github-repo-apps-2020-05-01-19-12-16-GDDP4GZR.png" width="2066" height="856"/></div><p>所以,我们在Netlify添加github的仓库时,实际上是授权Netlify在github的app访问某个仓库的权限。</p><p>一旦有代码push或者PR,Netlify在github的app都能收到通知然后进行相应地处理。</p><p>好了, 这种部署方式的原理大概说清楚了。接下来简单地讲一下操作步骤。</p><ol><li>用githbu登录 <a href="https://app.netlify.com/">https://app.netlify.com/</a></li><li>点击&quot;New site from git&quot;</li><li>Netlify会提示需要额外的权限以便于站点部署,选择仅给予指定仓库权限,然后选择 ttys3/nanodm.net 这个仓库</li></ol><div><img alt="netlify-choose-repo" src="https://ttys3.dev/static/assets/netlify-choose-repo-2020-05-01-18-40-41-ZAYITUVZ.png" width="1632" height="1132"/></div><div><img alt="github-netlify-app-config" src="https://ttys3.dev/static/assets/github-netlify-app-config-2020-05-01-19-10-33-JQOW6F4P.png" width="1482" height="1152"/></div><ol start="4"><li>配置构建方式为<code>hugo</code>并部署站点</li></ol><div><img alt="netlify-deploy-config" src="https://ttys3.dev/static/assets/netlify-deploy-config-2020-05-01-19-20-38-SGG2MDTE.png" width="1732" height="1748"/></div><ol start="5"><li>域名配置</li></ol><p>部署成功,Netlify会自动分配一个随机的域名给你。我们可以自行修改成方便记忆的,比如我这里使用的 <code>nanodm.netlify.app</code>。</p><div><img alt="netlify-domain-settings" src="https://ttys3.dev/static/assets/netlify-domain-settings-2020-05-01-19-23-42-7SRZQWDV.png" width="1890" height="630"/></div><p><code>xxx.netlify.app</code> 这个域名太长了,太难记了,因此,当然是要设置自定义域名了。 Netlify设置自定义域名是完全免费的。但是<a href="https://docs.netlify.com/domains-https/custom-domains/#definitions">官方的文档</a>可能看起来没那么简洁明了。 因此老灯这里特别说明一下,加自定义域名,就是加一个CNAME记录指向你当前的<code>xxx.netlify.app</code> 这个域名。</p><p>老灯以CloudFlare为例:</p><div><img alt="cf-config-netlify-custom-domain" src="https://ttys3.dev/static/assets/cf-config-netlify-custom-domain-2020-05-01-19-28-32-GMR33HGP.png" width="2138" height="648"/></div><p>注意这里启用了CF的Proxy功能,为什么呢?因为老灯的域名是托管在CF的,主要是CF可以自动https. 当然,Netlify也是完全支持自动ACME申请Let&#x27;s Encrypt的证书的,但是前提是你的域名要使用Netlify的DNS. Netlify也支持手动设置SSL证书,当然,这个基本上咱不考虑了,都2020年了,谁还手动设置证书呢?</p><p>DNS CNAME配置好之后,我们就可以在Netlify Custom domains那里添加上这个域名了。 注意顺序,一定是先设置好CNAME记录,再到Netlify添加,因为Netlify并不能确定这个域名是不是你的, 所以,它的处理方法也很简单,在你点击提交的时候,它会校验这个域名的CNAME记录的值,是不是对应了你的<code>xxx.netlify.app</code> 这个域名</p><div><img alt="" src="https://ttys3.dev/static/assets/netlify-custom-domains-ok-2020-05-01-19-34-40-WXT2OKPV.png" width="2484" height="1106"/></div><p>好了,现在就能用自定义域名访问了。</p><p>整个过期是不是非常简单? 总结起来就是, push一个仓库到github, 在netlify选中这个仓库部署。嗯,就这样,一个站点就好了。 自定义DNS是额外的可选操作。用netlify提供的域名也是OK的。</p><p>要查看部署好的站点,请访问: <a href="https://nanodm.net/">https://nanodm.net/</a></p><h2 id="其它"><a href="#其它" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它</h2><h3 id="netlify构建失败处理"><a href="#netlify构建失败处理" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Netlify构建失败处理</h3><p>由于本地环境和Netlify的构建环境还明些差异的,如果遇到构建失败,可以通过查看log定位问题。 比如老灯这里,把even这个主题升级到最新版之后,发现在Netlify构建失败了。</p><div><img alt="netlify-build-log" src="https://ttys3.dev/static/assets/netlify-build-log-2020-05-01-18-33-01-4Q6G5LRO.png" width="2566" height="1636"/></div><div><img alt="netlify-hugo-build-failed" src="https://ttys3.dev/static/assets/netlify-hugo-build-failed-log-2020-05-01-18-34-32-UIRAO6SI.png" width="2412" height="894"/></div><p>解决办法: 仓库根目录下增加<code>netlify.toml</code>配置文件指定hugo版本, 当前最新版本为 0.69.2, 老灯就指定<code>HUGO_VERSION = &quot;0.69.2&quot;</code></p><p>hugo当前最新版本号可以去 <a href="https://github.com/gohugoio/hugo/releases">https://github.com/gohugoio/hugo/releases</a> 查看</p><div class="relative"><pre><code class="language-toml code-highlight"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">context.production.environment</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token key property">HUGO_VERSION</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.69.2&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">context.deploy-preview.environment</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token key property">HUGO_VERSION</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.69.2&quot;</span> </span></code></pre></div><h3 id="自定义部署命令"><a href="#自定义部署命令" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>自定义部署命令</h3><p>Netlify支持通过 <code>netlify.toml</code>配置文件 来配置构建。</p><p>老灯的配置文件如下:</p><div class="relative"><pre><code class="language-toml code-highlight"><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">build</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">publish</span> <span class="token punctuation">=</span> <span class="token string">&quot;public&quot;</span> </span><span class="code-line"><span class="token key property">command</span> <span class="token punctuation">=</span> <span class="token string">&quot;env TZ=&#x27;Asia/Shanghai&#x27; hugo --gc --minify --enableGitInfo&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">context.production.environment</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token key property">HUGO_VERSION</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.69.2&quot;</span> </span><span class="code-line"> <span class="token key property">HUGO_ENV</span> <span class="token punctuation">=</span> <span class="token string">&quot;production&quot;</span> </span><span class="code-line"> <span class="token key property">HUGO_ENABLEGITINFO</span> <span class="token punctuation">=</span> <span class="token string">&quot;true&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">context.deploy-preview</span><span class="token punctuation">]</span> </span><span class="code-line"><span class="token key property">command</span> <span class="token punctuation">=</span> <span class="token string">&quot;hugo --gc --minify --buildFuture -b $DEPLOY_PRIME_URL&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span><span class="token class-name table">context.deploy-preview.environment</span><span class="token punctuation">]</span> </span><span class="code-line"> <span class="token key property">HUGO_VERSION</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.69.2&quot;</span> </span><span class="code-line"> <span class="token key property">HUGO_ENV</span> <span class="token punctuation">=</span> <span class="token string">&quot;production&quot;</span> </span><span class="code-line"> <span class="token key property">HUGO_ENABLEGITINFO</span> <span class="token punctuation">=</span> <span class="token string">&quot;true&quot;</span> </span></code></pre></div><p>Netlify会自动从这个配置文件读取配置,可以在Netlify 配置面看到这个文件配置是生效的:</p><div><img alt="netlify-file-config" src="https://ttys3.dev/static/assets/netlify-file-config-2020-05-01-19-41-48-VQD3275P.png" width="2062" height="768"/></div><p>通过构建log我们可以验证,Netlify是不是执行了我们配置的命令:</p><div><img alt="hugo-custom-build-command-on-netlify" src="https://ttys3.dev/static/assets/hugo-custom-build-command-on-netlify-2020-05-01-18-50-32-L5GT7O2A.png" width="2306" height="1280"/></div><p>另外,Netlify还有很多有趣的功能,大家感兴趣的可以慢慢玩。</p><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://gohugo.io/hosting-and-deployment/hosting-on-netlify/">https://gohugo.io/hosting-and-deployment/hosting-on-netlify/</a></p><p><a href="https://docs.netlify.com/domains-https/custom-domains/#definitions">https://docs.netlify.com/domains-https/custom-domains/#definitions</a></p><p><a href="https://docs.netlify.com/large-media/setup/">https://docs.netlify.com/large-media/setup/</a></p> Fri, 01 May 2020 09:47:12 GMT ttyS3 netlifyhugo https://ttys3.dev/blog/fedora31-upgrade-to-fedora32 Fedora 31 升级到 Fedora 32 https://ttys3.dev/blog/fedora31-upgrade-to-fedora32 <p>老灯一个10多年的ArchLinux用户, 这么多年啊, 一直用Arch滚啊滚啊,借用一下某电商的广告台词就是:</p><blockquote><p>Arch滚动一时爽,一直滚动一直爽。</p><p>一时升级一时爽,一直升级一直爽!!</p></blockquote><p>滚动升级是爽了,但是天天滚,对于升级这种事也就没有什么”激情“了。甚至都升级升得想吐了。有时候一天能更新好几次。</p><p>这不,老灯前面更换到Fedora, 终于等来了这次的”大版本“升级体验了。心情居然还有点小激动。</p><p>毕竟下次再升级还得期待半年呢(Fedora固定6个月发布一个大版本)。这真是:</p><blockquote><p>Fedora升级一时爽, 半年升级等半年。</p></blockquote><h2 id="fedora-32-更新了啥"><a href="#fedora-32-更新了啥" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Fedora 32 更新了啥</h2><p>Fedora 32 原定于2020年4月21日发布的,由于bug问题推迟发布了一周。 对此phoronix有报导,见<a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=Fedora-32-Release-Bug-Delay">Fedora 32 Delayed From Releasing Next Week Due To Bugs</a></p><blockquote><p>The current <a href="https://qa.fedoraproject.org/blockerbugs/milestone/32/final/buglist">blocker bugs</a> include Fedora&#x27;s &quot;rescue mode&quot; not recognizing LVM partitions and the F32 backgrounds version not being in the stable repository. There are also freeze exceptions around issues with some dual GPU laptops, the KDE desktop session not starting when switching between users, and other rather minor items.</p></blockquote><p>4月28号,F32准时发布了。</p><p>phoronix 报导: <a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=Fedora-32-Released">https://www.phoronix.com/scan.php?page=news_item&amp;px=Fedora-32-Released</a></p><p>官方博客有简单的说明: <a href="https://fedoramagazine.org/whats-new-fedora-32-workstation/">https://fedoramagazine.org/whats-new-fedora-32-workstation/</a></p><p>更详细的说明在 <a href="https://fedoraproject.org/wiki/Releases/32/ChangeSet?rd=Releases/32">https://fedoraproject.org/wiki/Releases/32/ChangeSet?rd=Releases/32</a></p><p>主要更新:</p><ul><li><p>内核从 5.5.x 更新到 5.6.7</p></li><li><p>默认启用 EarlyOOM</p><blockquote><p>安装Earlyoom软件包,并默认启用它。 如果RAM和swap都低于10%,则EarlyOOM将SIGTERM发送给具有最大oom_score的进程。 如果RAM和swap都低于5%,则EarlyOOM将SIGKILL发送给具有最大oom_score的进程。 这个想法是要尽快从内存不足的情况中恢复,而不是典型的整个系统挂起(假死)使用户不得不关闭电源而没有其他选择的。</p></blockquote><p>我觉得这个特性还是挺赞的,特别是对于小内存机器。 那么为什么叫EarlyOOM?因为Linux机器默认就有OOM的。 OOM是Out of Memory的缩写,内存不足的意思。当内存严重不足时,内核就会调用 OOM 终结者杀死oom_score超标的进程。</p><div><img alt="terminator" src="https://ttys3.dev/static/assets/terminator-2020-04-29-22-46-51-WS464WUZ.png" width="1196" height="736"/></div><p>这位同志,你吃内存吃太多了,没说,Chrome同志,说的就是你,你赶紧的,从食堂给我离开!</p><p>OOM终结者是怎么选择应该杀死哪个进程的呢? Linux内核为每个正在运行的进程oom_score评分,该评分显示了在可用内存不足的情况下终止该进程的可能性。 得分与该进程使用的内存量成正比。oom_score评分 = 10 x 进程的内存使用百分比(x%中的x)。 因此,最大分值为 100(百分之100) x 10 = 1000. 此外,如果进程以特权用户身份运行,则与普通用户进程使用相同的内存相比,该进程的oom_score略低。</p><p>可以在/proc目录中找到进程的oom_score。 假设进程ID(pid)为42, 执行<code>cat /proc/42/oom_score</code>即可提到该进程的当前的OOM得分。</p><p>进程使用的内存我们可以用htop或top查看,然后按m和M切换排序。 内核对象使用的内存可以通过以下命令:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># awk &#x27;{printf &quot;%5d MB %s\n&quot;, $3*$4/(1024*1024), $1}&#x27; &lt; /proc/slabinfo | sort -n</span> </span></code></pre></div><p>那么既然内核已经有OOM机制了,为什么还要引入一个EarlyOOM ? 我们看看OOM的判断条件是什么:</p><p>根据文档 <a href="https://www.kernel.org/doc/gorman/html/understand/understand016.html">https://www.kernel.org/doc/gorman/html/understand/understand016.html</a> :</p><ul><li>Is there enough swap space left (nr_swap_pages &gt; 0) ? If yes, not OOM</li><li>Has it been more than 5 seconds since the last failure? If yes, not OOM</li><li>Have we failed within the last second? If no, not OOM</li><li>If there hasn&#x27;t been 10 failures at least in the last 5 seconds, we&#x27;re not OOM</li><li>Has a process been killed within the last 5 seconds? If yes, not OOM</li></ul><p>我们可以发现,OOM终结者在杀死一个进程之前的决定还是很谨慎的。比如上面描述的很多条件下都会判断为<code>not OOM</code>。 实际发生OOM时,系统很可能UI界面无法响应了(比如GNOME卡死了)。 <code>EarlyOOM</code> 能够确保RAM和swap中至少有一个是可用大于10%的。 在小于10%的时候,EarlyOOM终结者采取温和的劝退策略,Chrome同志,你吃内存吃太多了,你先自行退出吧(SIGTERM信号)。 在小于5%的时候,EarlyOOM终结者发现Chrome又跑回来了,EarlyOOM非常地生气, 则直接拿枪把它”突突突“了(SIGKILL信号)。</p><div><img alt="chrome-ram-killer" src="https://ttys3.dev/static/assets/chrome-ram-killer-2020-04-29-23-17-07-GDP6CZFC.png" width="659" height="374"/></div></li><li><p>SSD默认启用TRIM <a href="https://fedoraproject.org/wiki/Changes/EnableFSTrimTimer">https://fedoraproject.org/wiki/Changes/EnableFSTrimTimer</a></p></li></ul><blockquote><p>启用<code>fstrim.timer</code>将导致<code>fstrim.service</code>每周执行,这顺带执行<code>/usr/sbin/fstrim --fstab --verbose --quiet</code>, 所述fstrim命令通知存储设备(物理和虚拟的)关于未使用的块。这提示可以使耗损均衡和块擦除更有效率,并通过将空闲逻辑盘区返回到精简池(the thin pool)来提高LVM自动精简配置(thin provisioning)上的空闲逻辑盘区的利用率。</p></blockquote><div><img alt="fstrim.timer-status" src="https://ttys3.dev/static/assets/fstrim.timer-status2020-04-30-03-23-15-ZZ4TIQBQ.png" width="1500" height="342"/></div><ul><li><p>GNOME 3.36</p><ul><li><p>性能提升</p></li><li><p>视觉效果改进</p></li><li><div><img alt="gnome-3.36-new-extensions-app" src="https://ttys3.dev/static/assets/gnome-3.36-new-extensions-app-2020-04-30-00-18-11-IQUWRL2P.png" width="1648" height="1912"/></div></li><li><p>默认app变更:</p><ul><li>Shotwell (image viewer and manager) is replaced by <strong>Photos</strong>.</li><li>Evolution (email client) is replaced by <strong>Geary</strong>.</li><li>Rhythmbox (music player for a long time in GNOME) is replaced by <strong>Music</strong>.</li></ul></li><li><p>优化Settings菜单组织</p></li></ul><div><img alt="gnome-3.36-new-about" src="https://ttys3.dev/static/assets/gnome-3.36-new-about-2020-04-29-23-28-24-ZFT6WALX.png" width="2136" height="1642"/></div><p>你可能会发现一个细节,我这里的<code>Windowing System</code>显示的是<code>X11</code>,原因是我使用了Nvidia的闭源驱动(the proprietary nvidia driver)。</p><p>GNOME博客的这个文章解释得很清楚: <a href="https://blogs.gnome.org/uraeus/2019/09/23/fedora-workstation-31-whats-new/">https://blogs.gnome.org/uraeus/2019/09/23/fedora-workstation-31-whats-new/</a></p><blockquote><p>In Fedora Workstation 31 Wayland is still disabled by default if you use the Nvidia binary driver. The reason for this is due to lack of acceleration under XWayland, meaning that any application depending on GLX, like a lot of games, will just get software GL rendering with the binary NVidia driver. This isn’t something we can resolv on our own, Nvidia has to do the work since its their closed source driver, but we been discussing it regularly with them and we been told now that they are looking at the work Adam Jackson some time ago which was specifically aimed at helping them bring their X.org driver to XWayland. We don’t have a timeline yet, but it is being actively looked at and hopefully a proper date can be provided soon. I am actually running Fedora Workstation 31 using the NVidia driver myself at the moment on this laptop, and for those interested in helping dogfood this setup, in preparation for hopefully being able to enable Wayland on NVidia in Fedora Workstation 32, it is fairly simple thing to do. Under /usr/lib/udev/rules.d/ you find a file called 61-gdm.rules, just edit that file and comment out (#) the line that reads ‘DRIVER==&quot;nvidia&quot;, RUN+=&quot;/usr/libexec/gdm-disable-wayland&quot;‘ and you will revert to a standard setup where your standard session is a Wayland session, but with a x.org session available as a fallback. The more people that run this and report issues the better as it helps us make this rock solid before releasing it upon the world.</p></blockquote><p>已经F32了,我们看看这个限制是否默认移除了?</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">/usr/lib/udev/rules.d </span><span class="code-line">❯ <span class="token function">cat</span> <span class="token number">61</span>-gdm.rules </span><span class="code-line"><span class="token comment"># disable Wayland on Cirrus chipsets</span> </span><span class="code-line">ATTR<span class="token punctuation">{</span>vendor<span class="token punctuation">}</span><span class="token operator">==</span><span class="token string">&quot;0x1013&quot;</span>, ATTR<span class="token punctuation">{</span>device<span class="token punctuation">}</span><span class="token operator">==</span><span class="token string">&quot;0x00b8&quot;</span>, ATTR<span class="token punctuation">{</span>subsystem_vendor<span class="token punctuation">}</span><span class="token operator">==</span><span class="token string">&quot;0x1af4&quot;</span>, ATTR<span class="token punctuation">{</span>subsystem_device<span class="token punctuation">}</span><span class="token operator">==</span><span class="token string">&quot;0x1100&quot;</span>, <span class="token variable assign-left">RUN</span><span class="token operator">+=</span><span class="token string">&quot;/usr/libexec/gdm-disable-wayland&quot;</span> </span><span class="code-line"><span class="token comment"># disable Wayland on Hi1710 chipsets</span> </span><span class="code-line">ATTR<span class="token punctuation">{</span>vendor<span class="token punctuation">}</span><span class="token operator">==</span><span class="token string">&quot;0x19e5&quot;</span>, ATTR<span class="token punctuation">{</span>device<span class="token punctuation">}</span><span class="token operator">==</span><span class="token string">&quot;0x1711&quot;</span>, <span class="token variable assign-left">RUN</span><span class="token operator">+=</span><span class="token string">&quot;/usr/libexec/gdm-disable-wayland&quot;</span> </span><span class="code-line"><span class="token comment"># disable Wayland when using the proprietary nvidia driver</span> </span><span class="code-line"><span class="token variable assign-left">DRIVER</span><span class="token operator">==</span><span class="token string">&quot;nvidia&quot;</span>, <span class="token variable assign-left">RUN</span><span class="token operator">+=</span><span class="token string">&quot;/usr/libexec/gdm-disable-wayland&quot;</span> </span><span class="code-line"><span class="token comment"># disable Wayland if modesetting is disabled</span> </span><span class="code-line">IMPORT<span class="token punctuation">{</span>cmdline<span class="token punctuation">}</span><span class="token operator">=</span><span class="token string">&quot;nomodeset&quot;</span>, <span class="token variable assign-left">RUN</span><span class="token operator">+=</span><span class="token string">&quot;/usr/libexec/gdm-disable-wayland&quot;</span> </span></code></pre></div><p>not good, <code>disable Wayland when using the proprietary nvidia driver</code>依旧存在。看来还是要等nvidia官方把XWayland支持加上了。</p></li><li><p>GCC 10 <a href="https://fedoraproject.org/wiki/Changes/GCC10">https://fedoraproject.org/wiki/Changes/GCC10</a></p><p>GCC 10的重大改进应该是新增加的静态分析功能吧,见 <a href="https://developers.redhat.com/blog/2020/03/26/static-analysis-in-gcc-10/">https://developers.redhat.com/blog/2020/03/26/static-analysis-in-gcc-10/</a></p></li><li><p>Glibc 2.31 <a href="https://fedoraproject.org/wiki/Changes/GLIBC231">https://fedoraproject.org/wiki/Changes/GLIBC231</a></p></li><li><p>LLVM 10 <a href="https://fedoraproject.org/wiki/Changes/LLVM-10">https://fedoraproject.org/wiki/Changes/LLVM-10</a></p></li><li><p>firewalld默认使用nftables后端 <a href="https://fedoraproject.org/wiki/Changes/firewalld_default_to_nftables">https://fedoraproject.org/wiki/Changes/firewalld_default_to_nftables</a></p><p>这个改动应该是比较大的. ntf跟iptables相比,还是很新的一个东西。像docker这种一直还坚守在老的iptables上面,会容易造成问题。不过,其实在Fedroa上面完全不是问题,反正从RHEL 8起就不能跑docker了。它自家的podman自然是跟firewalld配合得比较好的。</p><ul><li><p>libvirt libvirt already cooperates with the firewalld nftables backend. The only thing needed is to test/verify.</p></li><li><p>podman libvirt already cooperates with the firewalld nftables backend. The only thing needed is to test/verify.</p></li><li><p>docker Docker currently does not cooperate with the nftables backend. It currently side-steps firewalld by injecting its own rules in iptables ahead of firewalld&#x27;s rules. However, with the nftables backend firewalld&#x27;s rule will still be evaluated. Netfilter in the kernel will call iptables, then nftables for the same packet. This means firewalld/nftables is likely to drop the packet even if docker has iptables rules to ACCEPT.</p><p>Proposed fix 1: Docker package should provide a firewalld zone definition that includes the docker interfaces (e.g. docker0). The zone should use the &quot;ACCEPT&quot; policy (firewalld --set-target). This will allow docker&#x27;s traffic to pass through firewalld/nftables. Issue 1: If a user has configured a different docker bridge name, then they&#x27;ll have to manually add the bridge to the docker zone (or firewalld&#x27;s trusted zone).</p><p>Proposed fix 2: Just like &quot;Proposed fix 1&quot;, but instead of adding the zone definition to docker we created a &quot;docker-firewalld&quot; (or firewalld-docker?) package that has the zone definition. This could be installed by default when docker is installed.</p></li></ul></li><li><p>程序语言相关</p><ul><li><p>Python 3.8 <a href="https://fedoraproject.org/wiki/Changes/Python3.8">https://fedoraproject.org/wiki/Changes/Python3.8</a></p><p>Python版本从 Python 3.7 升级到 Python 3.8</p></li><li><p>Python 2 彻底退休</p><p>The python2 package and all its subpackages will be removed from Fedora 32. A legacy python27 package for developers and users will be provided. All packages in Fedora that need Python 2 to run will be removed from Fedora 32 regardless of their dependencies. All packages in Fedora that need Python 2 to build will be removed from Fedora 32 regardless of their dependencies. Exceptions can be granted by FESCo.</p></li><li><p>Deprecate python-nose <a href="https://fedoraproject.org/wiki/Changes/DeprecateNose">https://fedoraproject.org/wiki/Changes/DeprecateNose</a></p><p>The python-nose (python3-nose) package will be deprecated in Fedora 32. Nose is dead upstream, but far too many packages still BuildRequire it, so we cannot remove it yet. Packagers are encouraged to switch to python3-pytest or python3-nose2, but python3-nose remains available for the time being.</p></li><li><p>Python3-rdiff-backup <a href="https://fedoraproject.org/wiki/Changes/Python3-rdiff-backup">https://fedoraproject.org/wiki/Changes/Python3-rdiff-backup</a></p></li><li><p>Build Python with -fno-semantic-interposition for better performance <a href="https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup">https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup</a></p><p>We add the -fno-semantic-interposition compiler/linker flag when building Python interpreters, as it provides significant performance improvement, up to 27% depending on the workload. Users will no longer be able to use LD_PRELOAD to override a symbol from libpython, which we consider a good trade off for the speedup.</p></li><li><p>Django 3</p></li><li><p>Ruby 2.7 &amp;&amp; Bundler 2.0</p></li><li><p>Golang 1.14</p></li><li><p>PHP 7.4 <a href="https://fedoraproject.org/wiki/Changes/php74">https://fedoraproject.org/wiki/Changes/php74</a></p></li><li><p>Mono 6.6</p><p>Update the Mono stack in Fedora from 5.20 to 6.6.</p></li><li><p>Switch mingw32 toolchain to dwarf-2 exceptions <a href="https://fedoraproject.org/wiki/Changes/Mingw32GccDwarf2">https://fedoraproject.org/wiki/Changes/Mingw32GccDwarf2</a></p><p>The main reason for switching to dwarf-2 is that rust can only be compiled to a MinGW toolchain targeting dwarf exceptions on 32-bit [4], and rust usage is starting to appear in some packages (i.e. librsvg2). Switching to dwarf-2 on mingw32 would hence allow to keep the same consistent package offering between mingw32 and mingw64, whereas otherwise one would need to either freeze the mingw32 variants at older versions, or remove them altogether.</p></li></ul></li><li><p>包管理相关</p><ul><li><p>新建用户相关:<a href="https://fedoraproject.org/wiki/Changes/Adopting_sysusers.d_format">启用sysusers.d目录</a> 当然,旧式的 useradd 命令方式添加用户也是支持的</p></li><li><p>rpm事务结束后重启相关服务 <a href="https://fedoraproject.org/wiki/Changes/Restart_services_at_end_of_rpm_transaction">https://fedoraproject.org/wiki/Changes/Restart_services_at_end_of_rpm_transaction</a></p><p>Scriptlets to restart each service that should be restarted in each rpm package will be replaced by a declaration in the unit file and an rpm transaction trigger that fires at the end and restarts all services.</p></li><li><p>Rebase apt package from apt-rpm to Debian&#x27;s apt <a href="https://fedoraproject.org/wiki/Changes/Move_apt_package_from_RPM_to_DPKG_backend">https://fedoraproject.org/wiki/Changes/Move_apt_package_from_RPM_to_DPKG_backend</a></p></li><li><p>Limit Scriptlet Usage of core packages <a href="https://fedoraproject.org/wiki/Features/LimitScriptletUsage">https://fedoraproject.org/wiki/Features/LimitScriptletUsage</a></p><p>Remove direct scriptlet calls from &quot;core packages&quot; (those that are used to build minimal container image). The packages can still affect changes during installation by placing files in the correct locations to trigger registered external programs.</p></li></ul></li><li><p>数据库</p><ul><li>MariaDB 10.4</li><li>PostgreSQL 12</li></ul></li></ul><h2 id="如何从f31升级到f32"><a href="#如何从f31升级到f32" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>如何从F31升级到F32</h2><h3 id="升级系统到f32"><a href="#升级系统到f32" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>升级系统到F32</h3><p>升级过程还是非常顺利的,基本上参数官方文档: <a href="https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/">https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/</a></p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># 首先确保系统更新到F31当前最新版</span> </span><span class="code-line"><span class="token function">sudo</span> dnf upgrade <span class="token variable parameter">--refresh</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 安装dnf system-upgrade 插件(如果没有安装过的话)</span> </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> dnf-plugin-system-upgrade </span><span class="code-line"><span class="token comment"># 下载升级文件, 注意这里的--releasever=32, 下次如果要升级到33, 只需要改动这里 --releasever=33 即可</span> </span><span class="code-line"><span class="token function">sudo</span> dnf system-upgrade download <span class="token variable parameter">--refresh</span> <span class="token variable parameter">--releasever</span><span class="token operator">=</span><span class="token number">32</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># 确认前面的操作都进行OK了,就可以执行以下命令开始升级</span> </span><span class="code-line"><span class="token function">sudo</span> dnf system-upgrade <span class="token function">reboot</span> </span></code></pre></div><p>我在升级过程中还是遇到点小问题的,比如这个:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">Error: </span><span class="code-line"> Problem: problem with installed package php-zmq-1.1.3-12.fc31.x86_64 </span><span class="code-line"> <span class="token attr-name key">- package php-zmq-1.1.3-12.fc31.x86_64 requires php(api)</span> <span class="token punctuation">=</span> <span class="token attr-value value">20180731-64, but none of the providers can be installed</span> </span><span class="code-line"> <span class="token attr-name key">- package php-zmq-1.1.3-12.fc31.x86_64 requires php(zend-abi)</span> <span class="token punctuation">=</span> <span class="token attr-value value">20180731-64, but none of the providers can be installed</span> </span><span class="code-line"> - php-common-7.3.17-1.fc31.x86_64 does not belong to a distupgrade repository </span><span class="code-line">(try to add &#x27;--skip-broken&#x27; to skip uninstallable packages) </span></code></pre></div><p>虽然提示说可以用<code>--skip-broken</code>, 但是这里我们只有一个php-zmq冲突,因此可以简单粗暴地卸载了php-common这个包完事: <code>sudo dnf remove php-common-7.3.17-1.fc31.x86_64</code> 系统升级之后再把php相关的包安装回来即可. 当然,也可以用<code>--skip-broken</code>参数。能解决问题就OK。</p><p>然后开始下载升级包:</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line">❯ <span class="token function">sudo</span> dnf system-upgrade download <span class="token variable parameter">--refresh</span> <span class="token variable parameter">--releasever</span><span class="token operator">=</span><span class="token number">32</span> </span><span class="code-line">Before you <span class="token builtin class-name">continue</span> ensure that your system is fully upgraded by running <span class="token string">&quot;dnf --refresh upgrade&quot;</span><span class="token builtin class-name">.</span> Do you want to <span class="token builtin class-name">continue</span> <span class="token punctuation">[</span>y/N<span class="token punctuation">]</span>: y </span><span class="code-line">Copr repo <span class="token keyword">for</span> bandwhich owned by atim <span class="token number">2.8</span> kB/s <span class="token operator">|</span> <span class="token number">3.3</span> kB 00:01 </span><span class="code-line">Copr repo <span class="token keyword">for</span> fira-code-fonts owned by evana <span class="token number">3.2</span> kB/s <span class="token operator">|</span> <span class="token number">3.3</span> kB 00:01 </span><span class="code-line">Adobe Systems Incorporated <span class="token number">773</span> B/s <span class="token operator">|</span> <span class="token number">2.9</span> kB 00:03 </span><span class="code-line">Fedora <span class="token number">32</span> openh264 <span class="token punctuation">(</span>From Cisco<span class="token punctuation">)</span> - x86_64 <span class="token number">62</span> B/s <span class="token operator">|</span> <span class="token number">543</span> B 00:08 </span><span class="code-line">Fedora Modular <span class="token number">32</span> - x86_64 <span class="token number">39</span> kB/s <span class="token operator">|</span> <span class="token number">6.5</span> kB 00:00 </span><span class="code-line">Fedora Modular <span class="token number">32</span> - x86_64 - Updates <span class="token number">6.8</span> kB/s <span class="token operator">|</span> <span class="token number">4.9</span> kB 00:00 </span><span class="code-line">Fedora <span class="token number">32</span> - x86_64 - Updates <span class="token number">5.5</span> kB/s <span class="token operator">|</span> <span class="token number">8.1</span> kB 00:01 </span><span class="code-line">Fedora <span class="token number">32</span> - x86_64 - Updates <span class="token number">302</span> kB/s <span class="token operator">|</span> <span class="token number">799</span> kB 00:02 </span><span class="code-line">Fedora <span class="token number">32</span> - x86_64 <span class="token number">1.6</span> kB/s <span class="token operator">|</span> <span class="token number">6.1</span> kB 00:03 </span><span class="code-line">RPM Fusion <span class="token keyword">for</span> Fedora <span class="token number">32</span> - Free - Updates <span class="token number">8.3</span> kB/s <span class="token operator">|</span> <span class="token number">3.6</span> kB 00:00 </span><span class="code-line">RPM Fusion <span class="token keyword">for</span> Fedora <span class="token number">32</span> - Free <span class="token number">3.0</span> kB/s <span class="token operator">|</span> <span class="token number">3.7</span> kB 00:01 </span><span class="code-line">RPM Fusion <span class="token keyword">for</span> Fedora <span class="token number">32</span> - Nonfree - Updates <span class="token number">21</span> kB/s <span class="token operator">|</span> <span class="token number">3.6</span> kB 00:00 </span><span class="code-line">RPM Fusion <span class="token keyword">for</span> Fedora <span class="token number">32</span> - Nonfree kB/s <span class="token operator">|</span> <span class="token number">3.7</span> kB 00:00 </span><span class="code-line">slack <span class="token number">427</span> B/s <span class="token operator">|</span> <span class="token number">1.0</span> kB 00:02 </span><span class="code-line">Visual Studio Code <span class="token number">1.7</span> kB/s <span class="token operator">|</span> <span class="token number">3.0</span> kB 00:01 </span><span class="code-line">Yarn Repository <span class="token number">4.7</span> kB/s <span class="token operator">|</span> <span class="token number">2.9</span> kB 00:00 </span><span class="code-line">Modular dependency problems: </span><span class="code-line"> </span><span class="code-line"> Problem <span class="token number">1</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:f31<span class="token punctuation">)</span> needed by module meson:latest:3120191009081836:dc56099c-0.x86_64 </span><span class="code-line"> Problem <span class="token number">2</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:f31<span class="token punctuation">)</span> needed by module ninja:latest:3120190304180949:f636be4b-0.x86_64 </span><span class="code-line"> Problem <span class="token number">3</span>: conflicting requests </span><span class="code-line"> - nothing provides module<span class="token punctuation">(</span>platform:f31<span class="token punctuation">)</span> needed by module ripgrep:latest:3120190803131619:22d7e2a5-0.x86_64 </span><span class="code-line">Dependencies resolved. </span><span class="code-line"><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span> </span><span class="code-line"> Package Architecture Version Repository Size </span><span class="code-line"><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span> </span><span class="code-line">Installing: </span><span class="code-line"> kernel x86_64 <span class="token number">5.6</span>.6-300.fc32 fedora <span class="token number">21</span> k </span><span class="code-line"> <span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span> 此处省略 </span><span class="code-line"> yum noarch <span class="token number">4.2</span>.19-1.fc32 fedora <span class="token number">46</span> k </span><span class="code-line"> zimg x86_64 <span class="token number">2.9</span>.2-1.fc32 fedora <span class="token number">271</span> k </span><span class="code-line">Resetting modules: </span><span class="code-line"> meson </span><span class="code-line"> ninja </span><span class="code-line"> ripgrep </span><span class="code-line"> </span><span class="code-line">Transaction Summary </span><span class="code-line"><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span> </span><span class="code-line">Install <span class="token number">49</span> Packages </span><span class="code-line">Upgrade <span class="token number">2191</span> Packages </span><span class="code-line">Remove <span class="token number">7</span> Packages </span><span class="code-line">Downgrade <span class="token number">34</span> Packages </span><span class="code-line"> </span><span class="code-line">Total download size: <span class="token number">2.6</span> G </span><span class="code-line">DNF will only download packages, <span class="token function">install</span> gpg keys, and check the transaction. </span><span class="code-line">Is this ok <span class="token punctuation">[</span>y/N<span class="token punctuation">]</span>: </span></code></pre></div><p>然后输入<code>y</code> 回车即开始下载了。 可以看到上面其实有个<code>Modular dependency problems</code>,但是被dnf自动解决了。</p><p>我安装了挺多东西的,详细的记录可点击这里查看 <a href="2020-04-28-f32-upgrade-log.txt">2020-04-28-f32-upgrade-log.txt</a></p><div><img alt="f32-upgrade-download-ok" src="https://ttys3.dev/static/assets/f32-upgrade-download-ok-2020-04-30-00-39-40-7AX5S7YM.png" width="3840" height="1554"/></div><p>下载OK了,就可以执行以下命令开始升级</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf system-upgrade <span class="token function">reboot</span> </span></code></pre></div><h3 id="更新f32系统到最新"><a href="#更新f32系统到最新" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>更新F32系统到最新</h3><p>这不是刚升级的系统么,怎么还要更新? 没错, 离F32发布其实已经有很多个小时了。在这段时间,有一些包可能已经有新版本了, 因此安装完系统,第一件事,就是把系统更新到最新。</p><h3 id="gnome-扩展更新"><a href="#gnome-扩展更新" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Gnome 扩展更新</h3><p>由于Gnome版本更新了,很多旧的扩展如果不更新会无法使用。 一般来说会自动更新的,如果没有自动,可以自行用Firefox打开 <a href="https://extensions.gnome.org/local/">https://extensions.gnome.org/local/</a> 选择需要更新的扩展进行更新。</p><h3 id="gnome-默认软件安装"><a href="#gnome-默认软件安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Gnome 默认软件安装</h3><p>前面有提到GNOME 3.36默认app变更。 由于我是升级过来的,因此新版本的GNOME默认软件并没有安装(比如 GNOME Music)。 F31默认的图片浏览器已经是<code>gnome-photos</code>了,因此不必重复安装。 邮件客户端<a href="https://wiki.gnome.org/Apps/Geary">Geary</a>可以选择性地安装,老灯试用了下感觉非常不错。 官方说这是“Email for humans”,我觉得符合实际。Geary非常轻量级,简洁,易用。Wikipedia也有介绍: <a href="https://en.wikipedia.org/wiki/Geary_(e-mail_client)">https://en.wikipedia.org/wiki/Geary_(e-mail_client)</a> Rhythmbox的默认地位已经被GNOME Music取代了,因此,当然是卸载Rhythmbox安装GNOME Music啦。</p><div class="relative"><pre><code class="language-bash code-highlight"><span class="code-line"><span class="token function">sudo</span> dnf remove <span class="token variable parameter">-y</span> rhythmbox </span><span class="code-line"><span class="token function">sudo</span> dnf <span class="token function">install</span> <span class="token variable parameter">-y</span> gnome-music gnome-extensions-app geary </span></code></pre></div><p>Geary 默认是三栏模式,最左边一栏默认的宽度下,导致Outlook的tags没法显示全,需要调宽一些。 这个最大宽度调整有些技巧,有时候你会发现无法向右拖动了,解决办法就是:将第二栏向右拖动了些。 然后第一栏就可以继续向右拖动了。</p><p>另外,由于我之前在<code>GNOME Settings</code>里的<code>Online Accounts</code>配置过Microsoft的账号,然后打开Geary惊喜地发现, 它可以直接使用<code>Online Accounts</code>里的账号,默认就打开了我的Outlook邮箱,体验还是挺不错的。</p><div><img alt="geary-mail-client" src="https://ttys3.dev/static/assets/geary-mail-client-2020-04-30-04-10-21-FB5XG2CK.png" width="2708" height="1348"/></div><div><img alt="geary-email-list-style" src="https://ttys3.dev/static/assets/geary-email-list-style-2020-04-30-04-17-35-3XV36U5A.png" width="2418" height="1180"/></div><p>按<code>F1</code>可以查看帮助文档(Geary’s built-in manual),文档挺全的,比较实用的是搜索相关的,比如:</p><table><thead><tr><th>搜索</th><th>说明</th></tr></thead><tbody><tr><td><code>is:read</code></td><td>已读邮件</td></tr><tr><td><code>is:unread</code></td><td>未读邮件</td></tr><tr><td><code>is:starred</code></td><td>星标邮件</td></tr><tr><td><code>subject:</code>text</td><td>查找标题包含text的邮件</td></tr><tr><td><code>from:</code>sender</td><td>查找发件人是sender的邮件</td></tr><tr><td><code>to:</code>recipient</td><td>查找收件人是recipient的邮件</td></tr><tr><td><code>body:</code>text</td><td>查找正文包含text的邮件</td></tr></tbody></table><p>默认只会下载最近2周的邮件,如果要下载更多,比如6个月,可以去Accounts里选择相应的邮箱账号 然后调整。</p><h2 id="参考文档"><a href="#参考文档" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>参考文档</h2><p><a href="https://fedoramagazine.org/upgrading-fedora-31-to-fedora-32/">https://fedoramagazine.org/upgrading-fedora-31-to-fedora-32/</a></p><p><a href="https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/">https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/</a></p><p><a href="https://fedoramagazine.org/whats-new-fedora-32-workstation/">https://fedoramagazine.org/whats-new-fedora-32-workstation/</a></p><p><a href="https://fedoraproject.org/wiki/Releases/32/ChangeSet">https://fedoraproject.org/wiki/Releases/32/ChangeSet</a></p><p><a href="https://www.kernel.org/doc/gorman/html/understand/understand016.html">https://www.kernel.org/doc/gorman/html/understand/understand016.html</a></p><p><a href="https://linux-mm.org/OOM">https://linux-mm.org/OOM</a></p><p><a href="https://dev.to/rrampage/surviving-the-linux-oom-killer-2ki9">https://dev.to/rrampage/surviving-the-linux-oom-killer-2ki9</a></p><p><a href="https://serverfault.com/questions/571319/how-is-kernel-oom-score-calculated">https://serverfault.com/questions/571319/how-is-kernel-oom-score-calculated</a></p> Wed, 29 Apr 2020 14:22:30 GMT ttyS3 fedoraupgradef32 https://ttys3.dev/blog/windows-terminal-msys2-mingw64-setup Win10终端神器——Windows Terminal 与 MSYS2 MinGW64 集成记 https://ttys3.dev/blog/windows-terminal-msys2-mingw64-setup <p>How to Install Zsh and Antibody(or Oh My Zsh) on Windows 10 without Windows Subsystem for Linux</p><p>老灯之前在公众号文章分享过<a href="https://mp.weixin.qq.com/s?__biz=MzU4NzcwMjk1Nw==&amp;mid=2247483967&amp;idx=1&amp;sn=01457006553d3d3ce81dd8aec166ceb3&amp;chksm=fde6b5fdca913ceb80e13e62d6438583edf14e3f29f88c9ef00da0c85a2d13311f035415b1b0&amp;token=2111349202&amp;lang=zh_CN#rd">《打造windows终端神器——MSYS2 MinGW64 与 Cmder 集成记【2020-03-03更新】》</a></p><p>然后我群里有朋友跟我说起了<a href="https://github.com/microsoft/terminal">Windows Terminal</a>, 都2020年了,还用Cmder那一套,是不是有点过时了?</p><p>然后我花了一些时间了解了下巨硬开源的这个Terminal.</p><div><img alt="" src="https://ttys3.dev/static/assets/win10-terminal-github-star-2020-04-19-00-17-36-6DLOWG3G.png" width="2118" height="806"/></div><p>60K star, 5.7K fork, 大家的期待应该还是蛮高的,毕竟cmd那个东西那么难用.</p><p>主要的开发语言为C++, 执行效率应该不用怀疑。</p><p>在github页面是这样描述自己的:</p><blockquote><p>Windows Terminal是一个新的,现代的,功能丰富的,高效的终端应用程序,适用于命令行用户。 它包括许多最经常使用的Windows命令行社区包括对标签的支持,丰富的文字,全球化,可配置,主题及造型,及其它功能。 该终端还需要满足我们的目标和措施,以确保它的快速,高效,并且不消耗大量的内存或电能。</p></blockquote><p>这里要注意的是, Windows Terminal 它是一个终端,它不是一个shell, 所以它并不是替换<code>cmd.exe</code>或<code>PowerShell</code>的。</p><p>它默认的profiles已经自带了<code>cmd.exe</code>和<code>PowerShell</code>的支持,因此本文关注的重点肯定也不是这些。要不然也没有必要写文章分享了。</p><p>本文的重点依旧是 MSYS2 + zsh.</p><p>注意: 由Cmder切换成Windows Terminal,它不会知道我们复制的是Windows路径但是要粘贴给zsh用, 因此不会有自动的Win到Linux的路径转换。</p><p>Windows Terminal里复制和粘贴已经默认内置快捷键:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">复制: ctrl + shift + c </span><span class="code-line">粘贴: ctrl + shift + v 或 鼠标右击 </span></code></pre></div><h2 id="1-安装windows-terminal"><a href="#1-安装windows-terminal" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>1. 安装Windows Terminal</h2><p>推荐的安装方式是从 <a href="https://aka.ms/windowsterminal">Microsoft Store</a> 安装Windows Terminal</p><p>注意系统要求: <code>Windows 10 version 18362.0 or higher</code></p><p>除了从store安装,也可以选择手动安装的方式,具体在github有说明: <a href="https://github.com/microsoft/terminal#other-install-methods">https://github.com/microsoft/terminal#other-install-methods</a></p><h2 id="2-安装msys2"><a href="#2-安装msys2" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2. 安装MSYS2</h2><p>这一部分基本上跟我公众号Cmder那篇文章保持一致。</p><p>为什么要用MSYS2 ? 因为它对开发者很友好, 在win下编译东西非常方便。 并且它使用了流行的Linux发行版<a href="https://www.archlinux.org/">ArchLinux</a>的pacman包管理,安装和升级安装都非常方便。 算下来,老灯用ArchLinux将近有10多年了,因此,看到这个Windows上的<code>pacman</code>简直是两眼放光。</p><p>首先我们下载安装 MSYS2 <a href="https://www.msys2.org/">https://www.msys2.org/</a> 安装主要有两点限制:</p><ul><li>MSYS2不能被安装到FAT*分区.</li><li>MSYS2不支持Windows XP,也就是你的系统至少要是Win Vista 之后。</li></ul><p>当然,我们现在用的是Win10,因此,这两个限制,基本上都可以忽略。</p><p>这里我们下载64位版本的, 为方便演示,我这里安装到 <code>C:\msys64</code></p><h3 id="21-msys2-镜像配置"><a href="#21-msys2-镜像配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>2.1 MSYS2 镜像配置</h3><p>国内如果直接通过msys2默认的源更新会相当慢,因此有必要配置一下国内镜像以加速下载.</p><p>进入 <code>C:\msys64\etc\pacman.d</code> , 下面有3个文件:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">mirrorlist.mingw32 </span><span class="code-line">mirrorlist.mingw64 </span><span class="code-line">mirrorlist.msys </span></code></pre></div><p>分别编辑其内容,在原文件的第一个 Server = 前一行插入中国镜像配置,结果如下:</p><p>mirrorlist.mingw32 内容如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment">##</span> </span><span class="code-line"><span class="token comment">## 32-bit Mingw-w64 repository mirrorlist</span> </span><span class="code-line"><span class="token comment">##</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">## Primary</span> </span><span class="code-line"><span class="token comment">## 清华大学软件镜像</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/i686/</span> </span><span class="code-line"><span class="token comment">## 中科大镜像</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirrors.ustc.edu.cn/msys2/mingw/i686/</span> </span><span class="code-line"><span class="token comment">## msys2.org</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://repo.msys2.org/mingw/i686/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://sourceforge.net/projects/msys2/files/REPOS/MINGW/i686/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://www2.futureware.at/~nickoe/msys2-mirror/mingw/i686/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirror.yandex.ru/mirrors/msys2/mingw/i686/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/i686</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirrors.ustc.edu.cn/msys2/mingw/i686</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirror.bit.edu.cn/msys2/REPOS/MINGW/i686</span> </span></code></pre></div><p>mirrorlist.mingw64 内容如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment">##</span> </span><span class="code-line"><span class="token comment">## 64-bit Mingw-w64 repository mirrorlist</span> </span><span class="code-line"><span class="token comment">##</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">## Primary</span> </span><span class="code-line"><span class="token comment">## 清华大学软件镜像</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/x86_64/</span> </span><span class="code-line"><span class="token comment">## 中科大镜像</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirrors.ustc.edu.cn/msys2/mingw/x86_64/</span> </span><span class="code-line"><span class="token comment">## msys2.org</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://repo.msys2.org/mingw/x86_64/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://sourceforge.net/projects/msys2/files/REPOS/MINGW/x86_64/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://www2.futureware.at/~nickoe/msys2-mirror/mingw/x86_64/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirror.yandex.ru/mirrors/msys2/mingw/x86_64/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/x86_64</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirrors.ustc.edu.cn/msys2/mingw/x86_64</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirror.bit.edu.cn/msys2/REPOS/MINGW/x86_64</span> </span></code></pre></div><p>mirrorlist.msys 内容如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment">##</span> </span><span class="code-line"><span class="token comment">## MSYS2 repository mirrorlist</span> </span><span class="code-line"><span class="token comment">##</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">## Primary</span> </span><span class="code-line"><span class="token comment">## 清华大学软件镜像</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/$arch</span> </span><span class="code-line"><span class="token comment">## 中科大镜像</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirrors.ustc.edu.cn/msys2/msys/$arch</span> </span><span class="code-line"><span class="token comment">## msys2.org</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://repo.msys2.org/msys/$arch/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://sourceforge.net/projects/msys2/files/REPOS/MSYS2/$arch/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://www2.futureware.at/~nickoe/msys2-mirror/msys/$arch/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirror.yandex.ru/mirrors/msys2/msys/$arch/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/$arch/</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirrors.ustc.edu.cn/msys2/msys/$arch</span> </span><span class="code-line"><span class="token attr-name key">Server</span> <span class="token punctuation">=</span> <span class="token attr-value value">http://mirror.bit.edu.cn/msys2/REPOS/MSYS2/$arch</span> </span></code></pre></div><p>安装完, 修改好镜像之后,更新一下软件:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">pacman <span class="token variable parameter">-Syu</span> </span></code></pre></div><h2 id="3-安装git-和-zsh"><a href="#3-安装git-和-zsh" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3. 安装git 和 zsh</h2><p>由于<a href="https://gitforwindows.org/">git for windows</a>使用了与原版msys2不兼容的底层库,(经过老灯长时间的使用), 发现通过pacman来安装git for windows的方式,容易导致一些问题,因此后面老灯都不使用pacman来安装git for windows了, 转而直接安装独立的git for windows.</p><p>尽管Git for Windows默认内置了一个 MSys2,单独安装git好像不太优雅?但是 —— 现在硬盘都是TB级别的了,谁还在乎这点空间?</p><p>但是使用单独的git for windows会带来另一个问题,由于git命令与当前shell(zsh.exe)处于两个不同的msys2环境中, 而这两个环境的底层库版本一般不同.</p><p>比如当我们需要在git 配置文件中配置netcat 作为ProxyCommand时,就会引发错误:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">$ <span class="token function">git</span> fetch origin win </span><span class="code-line"> <span class="token number">0</span> <span class="token punctuation">[</span>main<span class="token punctuation">]</span> <span class="token function">zsh</span> <span class="token punctuation">(</span><span class="token number">9972</span><span class="token punctuation">)</span> C:<span class="token punctuation">\</span>msys64<span class="token punctuation">\</span>usr<span class="token punctuation">\</span>bin<span class="token punctuation">\</span>zsh.exe: </span><span class="code-line">*** fatal error - cygheap base mismatch detected - 0x180331408/0x180317408. </span><span class="code-line">This problem is probably due to using incompatible versions of the cygwin DLL. </span></code></pre></div><p>因此,现在老灯建议,直接使用msys2提供的git兼容性更好.</p><p>安装方法:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">pacman <span class="token variable parameter">-S</span> <span class="token function">git</span> </span></code></pre></div><p>这里老灯还推荐一个git实用(装Bility)工具: <a href="https://github.com/o2sh/onefetch">https://github.com/o2sh/onefetch</a> , 取名onefetch的原因, 可能是有一个叫<code>neofetch</code>的用于显示系统信息的工具吧,这个的运行效果跟neofetch非常神似,效果如下:</p><div><img alt="" src="https://ttys3.dev/static/assets/onefetch-2020-04-19-02-35-12-5AH2J6YQ.png" width="1368" height="1196"/></div><h3 id="31-git-proxy配置"><a href="#31-git-proxy配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3.1 Git proxy配置</h3><p>针对不同的协议,git使用不同的代理。</p><ol><li>对于http/https协议,git可以直接配置全局代理:</li></ol><p>这里假设本地的http代理地址为:<a href="http://127.0.0.1:7070">http://127.0.0.1:7070</a></p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token function">git</span> config <span class="token variable parameter">--global</span> http.proxy http://127.0.0.1:7070 </span></code></pre></div><ol start="2"><li>对于ssh协议,git无法直接配置proxy</li></ol><p>我们要通过修改openssh客户端的配置文件 $HOME/.ssh/config:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">Host github.com </span><span class="code-line"> User git </span><span class="code-line"> ProxyCommand nc -x 127.0.0.1:1080 %h %p </span><span class="code-line"> </span><span class="code-line">Host bitbucket.org </span><span class="code-line"> User git </span><span class="code-line"> ProxyCommand nc -x 127.0.0.1:1080 %h %p </span></code></pre></div><p>另外不要忘记安装netcat, gnu的nc没有proxy参数(-x), 因此我们要选择openbsd版:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">pacman <span class="token variable parameter">-S</span> openbsd-netcat </span></code></pre></div><h3 id="32-ssh要不要安装"><a href="#32-ssh要不要安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3.2 SSH要不要安装?</h3><p>win10后面的版本基本上自带了openssh. 因此,我们可以直接在msys2 mingw64里使用ssh 这个命令, 如果你用which 查一下,就能发现它的位置是:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">$ <span class="token function">which</span> <span class="token function">ssh</span> </span><span class="code-line">/c/Windows/System32/OpenSSH/ssh </span></code></pre></div><p>也就是 <code>C:\Windows\System32\OpenSSH\ssh.exe</code></p><p>但是前面我们通过pacman安装git时会默认安装依赖openssh, 因此,openssh的ssh客户端会有比windows自带的优先级更高.</p><p>ssh 的配置目录默认是在用户家目录下的<code>.ssh</code>目录。</p><h3 id="33-安装zsh"><a href="#33-安装zsh" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3.3 安装zsh</h3><p>为什么是zsh? bash无疑是兼容性最好的,但是zsh可能是除bash外使用人最多的shell之一了。 github有一个非常有名的项目叫:<code>ohmyzsh</code> 可以让你用zsh用到爽翻天。 然后自然的叫出:oh, my zsh! 这可能就是项目名称的由来吧。</p><p>安装 zsh</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line">pacman <span class="token variable parameter">-S</span> <span class="token function">zsh</span> </span></code></pre></div><p>zsh安装好后,我们就可以切换到它了, 由于mingw64并不是真正的Linux环境,因此也不支持chsh 直接切换shell.</p><h3 id="34-设置zsh为默认的shell"><a href="#34-设置zsh为默认的shell" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3.4 设置zsh为默认的shell</h3><p>由于msys2 指定 <code>MSYSCON</code> 为 <code>defterm</code> 时默认是执行bash.exe, 我们简单地把 <code>C:\msys64\msys2_shell.cmd</code> 大概第5行的bash改成zsh即可:</p><div class="relative"><pre><code class="code-highlight language-bat"><span class="code-line">set &quot;LOGINSHELL=zsh&quot; </span></code></pre></div><h3 id="35-msys2启用win原生链接"><a href="#35-msys2启用win原生链接" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>3.5 MSYS2启用win原生链接</h3><p>同样,编辑<code>C:\msys64\msys2_shell.cmd</code>,找到<code>rem To activate windows native symlinks uncomment next line</code>这一行, 即去掉 <code>set MSYS=winsymlinks:nativestrict</code> 前面的 rem 注释,变成:</p><div class="relative"><pre><code class="code-highlight language-bat"><span class="code-line">set MSYS=winsymlinks:nativestrict </span></code></pre></div><h2 id="4-等宽字体和windows-terminal主题安装"><a href="#4-等宽字体和windows-terminal主题安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4. 等宽字体和Windows Terminal主题安装</h2><h3 id="41-jetbrains-mono字体下载安装"><a href="#41-jetbrains-mono字体下载安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4.1 JetBrains Mono字体下载安装</h3><p>老灯之前是用购买的<code>Eco Coding</code>字段,后面换成了开源的<a href="https://github.com/tonsky/FiraCode">Fira Code</a>, 现在Jetbrains推出了非常给力的<a href="https://www.jetbrains.com/lp/mono/">JetBrains Mono</a>字体,老灯怎能不用?</p><p>下载建议直接去github: <a href="https://github.com/JetBrains/JetBrainsMono/releases">https://github.com/JetBrains/JetBrainsMono/releases</a></p><p>据老灯观察,官网更新没有github发布及时,比如当前官下载链接还是1.0.3, github已经是1.0.5了。</p><p>下载当前最新版:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">https://github.com/JetBrains/JetBrainsMono/releases/download/v1.0.5/JetBrainsMono-1.0.5.zip </span></code></pre></div><p>然后解压后会看到有很多目录(如下图),我们把所有不带<code>NL</code>(老灯猜测应该是No Ligatures的缩写)的字体都安装一次就OK。 无论是JetBrains Mono还是Fira Code,其Font Ligatures功能一直是一大特色,因此,选用这类字体, 当然还是要试一下带Ligatures版的。</p><div><img alt="" src="https://ttys3.dev/static/assets/jetbrains-mono-font-extracted-2020-04-19-01-47-14-I73CSUY6.png" width="1354" height="858"/></div><h3 id="42-windows-terminal主题安装"><a href="#42-windows-terminal主题安装" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>4.2 Windows Terminal主题安装</h3><p>Windows Terminal的配置文件位置比较隐蔽,为:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">C:\Users\你的用户名\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState </span></code></pre></div><p>如果在MSYS2里面,我们要把Windows路径自己翻译成Linux的:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">/c/Users/你的用户名/AppData/Local/Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState </span></code></pre></div><p>当然这里我们并不需要直接cd到这个目录编辑这个文件。直接在Windows Terminal的顶部菜单就可以选择编辑配置。</p><p>老灯一直比较喜欢<a href="https://github.com/morhetz/gruvbox">gruvbox</a> 这个配色,因此这里也以gruvbox为例。</p><p>编辑配置的时候,你会注意到有这么一行<code>// Add custom color schemes to this array</code>,表示我们可以在<code>schemes</code>这个 数组里加自定义的配色。这里老灯加的是<code>Gruvbox dark, soft</code>这个配色。</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"> <span class="token comment">// Add custom color schemes to this array</span> </span><span class="code-line"> <span class="token property">&quot;schemes&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span> </span><span class="code-line"> <span class="token comment">// Base 16 Gruvbox dark, soft 256 Color Configuration - Windows Terminal</span> </span><span class="code-line"> <span class="token comment">// Colors made by Dawid Kurek ([email protected]), morhetz (https://github.com/morhetz/gruvbox)</span> </span><span class="code-line"> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Gruvbox dark, soft&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;background&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#32302f&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;foreground&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#d5c4a1&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;black&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#32302f&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;red&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#fb4934&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;green&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#b8bb26&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;yellow&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#fabd2f&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;blue&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#83a598&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;magenta&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#d3869b&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;cyan&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#8ec07c&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;white&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#d5c4a1&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;brightBlack&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#665c54&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;brightRed&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#fb4934&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;brightGreen&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#b8bb26&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;brightYellow&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#fabd2f&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;brightBlue&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#83a598&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;brightMagenta&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#d3869b&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;brightCyan&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#8ec07c&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;brightWhite&quot;</span><span class="token operator">:</span> <span class="token string">&quot;#fbf1c7&quot;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token punctuation">]</span><span class="token punctuation">,</span> </span></code></pre></div><h2 id="5-增加msys2-profile"><a href="#5-增加msys2-profile" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>5. 增加MSYS2 profile</h2><p>直到现在,你在Windows Terminal新建tab, 还是发现不能打开MSYS2, 也没有这个选项,所以我们要把MSYS2加上。</p><p>我们加一个MSYS2配置吧,配置大概如下, 注意这里的<code>name</code>, <code>guid</code>, <code>startingDirectory</code>,<code>fontFace</code>, <code>commandline</code> 和 <code>colorScheme</code>, 这里的<code>guid</code>我直接用在线工具生成的,比如 <a href="https://www.guidgenerator.com/online-guid-generator.aspx">https://www.guidgenerator.com/online-guid-generator.aspx</a></p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"><span class="token punctuation">{</span> </span><span class="code-line"> <span class="token property">&quot;acrylicOpacity&quot;</span> <span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;closeOnExit&quot;</span> <span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;colorScheme&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Gruvbox dark, soft&quot;</span><span class="token punctuation">,</span> <span class="token comment">//Choose your color scheme here</span> </span><span class="code-line"> <span class="token property">&quot;commandline&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;C:/msys64/msys2_shell.cmd -defterm -no-start -use-full-path -here -mingw64&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;cursorColor&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;#FD9D4F&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;cursorShape&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;filledBox&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;fontFace&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;JetBrains Mono&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;fontSize&quot;</span> <span class="token operator">:</span> <span class="token number">12</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;guid&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;{8fc27f7a-7532-4e48-97cf-7d5df4cc40f0}&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;historySize&quot;</span> <span class="token operator">:</span> <span class="token number">9001</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;icon&quot;</span><span class="token operator">:</span> <span class="token string">&quot;C:/msys64/msys2.ico&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;name&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;MSYS2&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;padding&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;0, 0, 0, 0&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;snapOnInput&quot;</span> <span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;startingDirectory&quot;</span> <span class="token operator">:</span> <span class="token string">&quot;C:/Users/hacklog&quot;</span><span class="token punctuation">,</span> </span><span class="code-line"> <span class="token property">&quot;useAcrylic&quot;</span> <span class="token operator">:</span> <span class="token boolean">false</span> </span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">,</span> </span></code></pre></div><p>设置为默认profile:</p><div class="relative"><pre><code class="code-highlight language-json"><span class="code-line"> <span class="token property">&quot;defaultProfile&quot;</span><span class="token operator">:</span> <span class="token string">&quot;{8fc27f7a-7532-4e48-97cf-7d5df4cc40f0}&quot;</span><span class="token punctuation">,</span> </span></code></pre></div><p>好了, 鉴于改动还是有一些的,因此老灯这里也提供一下我的完整的配置文件下载(右击另存为):</p><p><a href="profiles.json.txt">profiles.json</a></p><p><a href="msys2_shell.cmd">msys2_shell.cmd</a></p><p><code>commandline</code> 即新建tab时如果选的这个profile,要启动什么命令。</p><p><code>set MSYSTEM=MINGW64 &amp; set MSYSCON=defterm &amp; set MSYS2_NOSTART=yes &amp; set MSYS2_PATH_TYPE=inherit &amp; set CHERE_INVOKING=1</code> “翻译” 成 msys2_shell.cmd 的参数分别是: <code>-mingw64 -defterm -no-start -use-full-path -here</code></p><p>细心的朋友就会发现,这实际上跟我公众号里Cmder那篇文章中的参数有些类似。 <code>-mingw64</code> 告诉 MSYS2 这个启动脚本,我们要启动的是mingw64, 不是mingw32, 也不是默认的msys2. <code>-defterm</code> 表示要启动的是bash,当然前面我们已经通过hacking方法让它默认变成了zsh了。 <code>-no-start</code> 表示不通过<code>start</code>命令来启动(因为这地弹出一个新的黑框框窗口,而我们的目的是要在Windows Terminal里跑的) <code>-use-full-path</code> 或 <code>set MSYS2_PATH_TYPE=inherit</code> 表示,我们在mingw64下面的时候, <code>PATH</code>环境变量的值继承自windows系统的环境变量。 <code>-here</code> 就是<code>set CHERE_INVOKING=1</code>的意思。 <code>set CHERE_INVOKING=1</code> 这是一个神奇的选项! 这个一定要设置. 不然我们设置的默认启动目录 参数对MSYS2 MinGW64会不生效. (关于这一点,我刚开始也是折腾了好久, 直到后来看到了zyzyz的文章)</p><blockquote><p>在Cygwin下面,如果CHERE_INVOKING 环境变量没有定义, Cygwin 会 cd到家目录作为启动目录, 设置 CHERE_INVOKING 为1 可以阻止这个行为. 似乎MSYS2 借用了这个技巧,因此我们可以直接使用这个.</p></blockquote><p>想了解更多详情,可以查阅: <a href="https://conemu.github.io/en/StartupDir.html">https://conemu.github.io/en/StartupDir.html</a> 和 <a href="https://conemu.github.io/en/CygwinStartDir.html">https://conemu.github.io/en/CygwinStartDir.html</a></p><p>所以,这就是为什么我们上面写的<code>commandline</code> 的值是<code>C:/msys64/msys2_shell.cmd -defterm -no-start -use-full-path -here -mingw64</code></p><p>好了,配置好了,我们看看效果:</p><div><img alt="" src="https://ttys3.dev/static/assets/win-term-new-msys2-tab-2020-04-19-02-14-04-C3OQZTQE.png" width="1071" height="662"/></div><div><img alt="" src="https://ttys3.dev/static/assets/win-term-msys2-pacman-2020-04-19-02-14-41-KKSP6IEB.png" width="2788" height="1642"/></div><div><img alt="" src="https://ttys3.dev/static/assets/win-term-zsh-2020-04-19-02-15-23-KB5KHLFU.png" width="1747" height="648"/></div><h2 id="zsh配置"><a href="#zsh配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>ZSH配置</h2><p>ZSH是神器,但是如果不配置好,也不能很好地发挥它的长处。</p><h3 id="安装antibody"><a href="#安装antibody" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>安装antibody</h3><p>没错, zsh有很多工具可以用来管理配置。最出名的要数<a href="https://github.com/ohmyzsh/ohmyzsh">ohmyzsh</a>, 目前github star数量为108K。</p><p>但是直接用ohmyzsh还是不太好,因为我们可能还想要加载别的插件。所以,需要一个插件管理器。</p><p>Antigen 就是这么一个插件管理器。</p><blockquote><p>Antigen is to zsh, what Vundle is to vim.</p></blockquote><p>虽然作者这样说,但是其实对于vim的插件管理器,老灯要推荐<a href="https://github.com/junegunn/vim-plug">vim-plug</a>。</p><p>但是这个插件本身是用shell写的,shell脚本的执行效率,在原生Linux下面可能不是问题,如果在Win10+MSYS2+MinGW64这种环境下,执行效率可能不会那么高了。</p><p>因此老灯又找到另一个基于golang的zsh插件管理器: antibody <a href="https://github.com/getantibody/antibody">https://github.com/getantibody/antibody</a></p><p>官方宣传语是:</p><blockquote><p>The fastest shell plugin manager. It is faster because it can do things concurrently, while Antigen does it sequentially. It also has the advantage of using a compiled language instead of a scripting one.</p></blockquote><p>官方描述也告诉了我们antibody更快的原因: 它更快是因为它可以并行处理,而Antigen只能顺序执行。</p><p>同时它还具有使用编译语言(antibody采用的是golang实现,一种非常高效的静态编译语言) 而不是脚本语言(antigen采用的是纯shell实现)的优点。</p><p>不过,antibody官方并不支持windows. 因为antibody实际上是zsh的一个扩展管理器。 像我们这样,在windows上面以zsh作为shell的人,还是比较少的。 因此,无灯花了一些时间进行了一些“魔改“,使得antibody可以很好地在 msys2 mingw64 + zsh 的环境下工作。</p><p>我已经编译好了windows 64位的: <a href="https://f.nanodm.net/Windows/shell/zsh/antibody.exe">https://f.nanodm.net/Windows/shell/zsh/antibody.exe</a></p><p>可以下载之后放到PATH路径下,比如<code>C:\msys64\usr\bin</code>下面都可以的。</p><p>编辑 <code>.zshrc</code> , 老灯的.zshrc配置内容如下:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token comment"># Created by HuangYeWuDeng</span> </span><span class="code-line"> </span><span class="code-line">autoload <span class="token variable parameter">-Uz</span> compinit </span><span class="code-line">compinit </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># prompt config</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">AGKOZAK_PROMPT_DIRTRIM</span><span class="token operator">=</span><span class="token number">10</span> </span><span class="code-line"><span class="token comment">#export AGKOZAK_MULTILINE=0</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># Load antibody</span> </span><span class="code-line"><span class="token comment"># export ANTIBODY_HOME=/c/Users/hacklog/.antibody</span> </span><span class="code-line"><span class="token builtin class-name">source</span> <span class="token operator">&lt;</span><span class="token punctuation">(</span>antibody init<span class="token punctuation">)</span> </span><span class="code-line">antibody bundle <span class="token operator">&lt;</span> ~/.zsh_plugins.txt </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token punctuation">[</span> <span class="token variable parameter">-e</span> ~/.zsh_alias <span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">source</span> ~/.zsh_alias </span><span class="code-line"><span class="token punctuation">[</span> <span class="token variable parameter">-e</span> ~/.zsh_compatible <span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">source</span> ~/.zsh_compatible </span><span class="code-line"> </span><span class="code-line"> </span><span class="code-line"><span class="token builtin class-name">alias</span> <span class="token variable assign-left">so</span><span class="token operator">=</span><span class="token string">&#x27;source ~/.zsh_alias&#x27;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">#golang</span> </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">GO111MODULE</span><span class="token operator">=</span>on </span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token variable assign-left">PKG_CONFIG_PATH</span><span class="token operator">=</span>/usr/local/lib/pkgconfig:<span class="token variable">$PKG_CONFIG_PATH</span> </span></code></pre></div><p>我的<code>.zsh_alias</code>配置内容如下:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">less</span><span class="token operator">=</span><span class="token string">&#x27;less -r&#x27;</span> <span class="token comment"># raw control characters</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">whence</span><span class="token operator">=</span><span class="token string">&#x27;type -a&#x27;</span> <span class="token comment"># where, of a sort</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">grep</span><span class="token operator">=</span><span class="token string">&#x27;grep --color&#x27;</span> <span class="token comment"># show differences in colour</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">egrep</span><span class="token operator">=</span><span class="token string">&#x27;egrep --color=auto&#x27;</span> <span class="token comment"># show differences in colour</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">fgrep</span><span class="token operator">=</span><span class="token string">&#x27;fgrep --color=auto&#x27;</span> <span class="token comment"># show differences in colour</span> </span><span class="code-line"><span class="token comment">#</span> </span><span class="code-line"><span class="token comment"># Some shortcuts for different directory listings</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">ls</span><span class="token operator">=</span><span class="token string">&#x27;ls -hF --color=tty&#x27;</span> <span class="token comment"># classify files in colour</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">dir</span><span class="token operator">=</span><span class="token string">&#x27;ls --color=auto --format=vertical&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">vdir</span><span class="token operator">=</span><span class="token string">&#x27;ls --color=auto --format=long&#x27;</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">ll</span><span class="token operator">=</span><span class="token string">&#x27;ls -l&#x27;</span> <span class="token comment"># long list</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">la</span><span class="token operator">=</span><span class="token string">&#x27;ls -A&#x27;</span> <span class="token comment"># all but . and ..</span> </span><span class="code-line"> <span class="token builtin class-name">alias</span> <span class="token variable assign-left">l</span><span class="token operator">=</span><span class="token string">&#x27;ls -CF&#x27;</span> <span class="token comment">#</span> </span></code></pre></div><p>我的 <code>.zsh_plugins.txt</code> (这个是antibody的配置文件,在家目录下,即跟.zshrc 在同一目录)文件内容如下:</p><div class="relative"><pre><code class="code-highlight language-bash"><span class="code-line"><span class="token comment">#oh my zsh</span> </span><span class="code-line"><span class="token comment">#robbyrussell/oh-my-zsh path:plugins/aws</span> </span><span class="code-line"> </span><span class="code-line">zsh-users/zsh-syntax-highlighting </span><span class="code-line">zsh-users/zsh-completions </span><span class="code-line"><span class="token comment">#see https://medium.com/@borekb/zsh-via-msys2-on-windows-3964a943b1ce</span> </span><span class="code-line"><span class="token comment">#asynchronous, dynamic color Git prompt for zsh https://github.com/agkozak/agkozak-zsh-prompt</span> </span><span class="code-line"><span class="token comment">#agkozak/agkozak-zsh-prompt</span> </span><span class="code-line"><span class="token comment">#https://github.com/borekb/agkozak-zsh-theme/tree/prompt-customization</span> </span><span class="code-line"><span class="token comment">#borekb/agkozak-zsh-theme branch:prompt-customization</span> </span><span class="code-line">https://bitbucket.org/ttys3/agkozak-zsh-prompt.git </span></code></pre></div><p>这里老灯只启用了3个扩展,一个高亮,一个自动完成的,还有一个prompt.</p><p>这个 agkozak ZSH Prompt 是异步prompt里唯一支持windows下的zsh的</p><p>为什么要异步的?比如prompt经常会显示一些git信息,这些实际上是要执行git命令来获取到的,对于同步的prompt,这些可能造成卡顿。</p><p>如果要加载 oh-my-zsh 的扩展,则格式如下:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">robbyrussell/oh-my-zsh path:plugins/插件目录名称 </span></code></pre></div><p>比如ArchLinux插件 <a href="https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/archlinux">https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/archlinux</a> 写成:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line">robbyrussell/oh-my-zsh path:plugins/archlinux </span></code></pre></div><p>(注:这里只是举例,实例上我们不可能会需要在Windows里用到archlinux的这个插件的)</p><p>其它有用的插件:</p><div class="relative"><pre><code class="code-highlight language-ini"><span class="code-line"><span class="token comment"># https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git</span> </span><span class="code-line">robbyrussell/oh-my-zsh path:plugins/git </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/cargo</span> </span><span class="code-line">robbyrussell/oh-my-zsh path:plugins/cargo </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/composer</span> </span><span class="code-line">robbyrussell/oh-my-zsh path:plugins/composer </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/kubectl</span> </span><span class="code-line">robbyrussell/oh-my-zsh path:plugins/kubectl </span><span class="code-line"> </span><span class="code-line"><span class="token comment"># https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/yarn</span> </span><span class="code-line">robbyrussell/oh-my-zsh path:plugins/yarn </span></code></pre></div><p>最后,文章有点长,如有错误,欢迎指正。</p><h2 id="本文参考"><a href="#本文参考" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>本文参考</h2><p><a href="https://github.com/microsoft/terminal">https://github.com/microsoft/terminal</a></p><p><a href="https://github.com/msys2/MSYS2-packages/issues/1684">https://github.com/msys2/MSYS2-packages/issues/1684</a></p><p><a href="https://github.com/microsoft/terminal/issues/1669#issuecomment-562082594">https://github.com/microsoft/terminal/issues/1669#issuecomment-562082594</a></p><p><a href="https://github.com/ShiromMakkad/base16-windows-terminal">https://github.com/ShiromMakkad/base16-windows-terminal</a></p><p><a href="https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingJsonSettings.md">https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingJsonSettings.md</a></p><p><a href="https://github.com/microsoft/terminal/blob/master/doc/cascadia/SettingsSchema.md">https://github.com/microsoft/terminal/blob/master/doc/cascadia/SettingsSchema.md</a></p><p><a href="https://github.com/microsoft/terminal/tree/master/src/tools/ColorTool">https://github.com/microsoft/terminal/tree/master/src/tools/ColorTool</a></p><p><a href="https://github.com/microsoft/terminal/tree/master/doc/user-docs">https://github.com/microsoft/terminal/tree/master/doc/user-docs</a></p><p><a href="https://github.com/microsoft/terminal/blob/master/doc/user-docs/ThirdPartyToolProfiles.md#msys2">https://github.com/microsoft/terminal/blob/master/doc/user-docs/ThirdPartyToolProfiles.md#msys2</a></p><p><a href="https://github.com/ShiromMakkad/base16-windows-terminal">https://github.com/ShiromMakkad/base16-windows-terminal</a></p> Sat, 18 Apr 2020 15:25:14 GMT ttyS3 Windows TerminalMSYS2MinGW64zshwindowsbase16antibodygruvbox https://ttys3.dev/blog/deploy-hugo-blog-witn-container 基于容器部署hugo博客 -- hugo个人博客折腾记之后篇 https://ttys3.dev/blog/deploy-hugo-blog-witn-container <p>这篇主要讲一下这个博客是怎么部署的</p><div class="relative"><pre><code class="code-highlight language-js"><span class="code-line"><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token operator">&lt;</span> music <span class="token string">&quot;32272267&quot;</span> <span class="token operator">&gt;</span><span class="token punctuation">}</span><span class="token punctuation">}</span> </span></code></pre></div><h2 id="hugo-主题选取"><a href="#hugo-主题选取" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>hugo 主题选取</h2><p>主题选取这个其实在<a href="/blog/new-blog-new-domain">前篇</a>已经说过了</p><p>这里说下这个主题的特点吧:</p><ol><li><p>5色可选。5种双色主题 (orange is default, red, blue, green, pink)可以直接在配置文件里修改。</p></li><li><p><a href="https://github.com/tonsky/FiraCode">Fira Code</a>作为默认等宽字体</p></li><li><p>响应式设计,各种分辨率浏览效果都不错</p></li><li><p>采用 <a href="https://prismjs.com/">PrismJS</a> 实现客户端代码高亮</p></li><li><p>最重要的是,它简洁。 没错,真的很简洁,没有过多的功能,甚至没有archive页面,没有tag cloud,只自带了3个shortcode。 对于hugo新手来说,越是简单的主题,你才越好下手修改。要不然刚接触hugo,就用了一个功能特别复杂的主题, 这对于掌握主题的DIY技能是没有帮助的。 现在你看到我的博客,我已经是根据自己的需求做了非常多的调整了。</p></li></ol><p>我调整后的terminal主题:</p><ol><li>同样5色可选。</li><li>使用<code>Jetbrains Mono</code> <a href="https://github.com/JetBrains/JetBrainsMono">https://github.com/JetBrains/JetBrainsMono</a> 等宽字体进行代码高亮</li><li>响应式设计保持不变</li><li>采用hugo自带的代码高亮方案(输出class) + 自定义的Gruvbox高亮配色</li><li>调整hugo默认的RSS 2.0 feed输出为atom输出,调整RSS摘要输出为全文输出</li><li>增加archive,tagcloud模板,增加基本的KaTex自动渲染LaTex支持。</li><li>增加TOC显示,返回TOP按钮,平滑滚动。</li><li>cover图片显示增加page bundle支持</li></ol><p>如果你碰巧也喜欢这个主题,老灯的代码是开放的,自取: <a href="https://github.com/ttys3/hugo-theme-terminal/tree/ttys3">https://github.com/ttys3/hugo-theme-terminal/tree/ttys3</a></p><h2 id="代码高亮"><a href="#代码高亮" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>代码高亮</h2><p>这里要说一下,在hugo里面,代码高亮有两种选择,一种是客户端实现方式,另一种是后端实现方式。 客户端实现就是用markdown的fenced code使代码在输出时保持原样(当然,跟html本身冲突的<code>&lt;</code>或<code>&gt;</code>会进行处理), 然后由客户端加载js进行高亮渲染。后端的方式,即是采用hugo默认的markdown解析引擎goldmark来调用 <a href="https://github.com/alecthomas/chroma">chroma</a>进行高亮渲染.</p><p>chroma跟python里的<a href="https://pygments.org/">Pygments</a> 采用一致的方式进行高亮,甚至连风格样式也保持一致。 所有Chroma的配色都是使用<code>_tools/style.py</code>脚本自Pygments的配色转换而来。 所以一般来说,这两个的渲染结果应该是一致的,Pygments有什么配色,chroma就有什么配色,自然, hugo就会有什么配色。配色效果可以去<a href="https://xyproto.github.io/splash/docs/">Chroma配色相册</a>查看</p><p>虽然Chroma是porting自Pygments, 但是也不是完全一样,比如作者解释了为什么Chroma比Pygments支持的高亮语言更少一些:</p><blockquote><p>I mostly only converted languages I had heard of, to reduce the porting cost.</p></blockquote><p>不过这完全不是问题,因为常用的语言它都支持了,而那些名字都没听过的语言,我也不需要高亮。</p><p>那么,既然hugo自带高亮, 主题也自带高亮,我是要用主题的前端方案呢?还是用后端的hugo方案呢?</p><h3 id="前后端高亮方案对比"><a href="#前后端高亮方案对比" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>前后端高亮方案对比</h3><table><thead><tr><th>对比项</th><th>hugo后端高亮</th><th>PrismJS前端高亮</th></tr></thead><tbody><tr><td>RSS feed输出</td><td>可保持高亮配色(当noClasses=true)</td><td>无高亮</td></tr><tr><td>浏览器兼容性</td><td>不相关</td><td>相关</td></tr><tr><td>inline CSS支持</td><td>支持</td><td>不支持</td></tr><tr><td>官方配色数量</td><td>较多</td><td>很少(8)</td></tr><tr><td>第三方配色数量</td><td>较多</td><td>较多</td></tr></tbody></table><p>看上去两者相比不分高下。所以,主要看需求了。 如果要求RSS feed输出也保持一致的代码高亮,则要使用hugo自带的高亮且启用inline CSS输出。</p><p>如果要求支持所有浏览器,则也应该选择hugo自带的方案。 see <a href="https://prismjs.com/index.html#limitations">PrimsJS Limitations</a></p><blockquote><p>No IE 6-10 support. If someone can read code, they are probably in the 85% of the population with a modern browser.</p></blockquote><p>如果是使用hugo自带的高亮且使用的是class的方式的话,我觉得应该用这两个都OK。 就看你喜欢的那个配色在对应的方案里有没有提供。</p><div class="relative"><pre><code class="code-highlight language-go"><span class="code-line"><span class="token keyword">package</span> main </span><span class="code-line"> </span><span class="code-line"><span class="token keyword">import</span> <span class="token string">&quot;fmt&quot;</span> </span><span class="code-line"> </span><span class="code-line"><span class="token comment">// This is a comment</span> </span><span class="code-line"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> </span><span class="code-line"> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">&quot;hello world&quot;</span><span class="token punctuation">)</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>输出对比: 我把二者的输出用在线工具格式化一下方便对比 <a href="https://codebeautify.org/htmlviewer/">https://codebeautify.org/htmlviewer/</a></p><p>PrismJS</p><div class="relative"><pre><code class="code-highlight language-html"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>pre</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token css language-css value"><span class="token property">color</span><span class="token punctuation">:</span><span class="token color hexcode">#f8f8f2</span><span class="token punctuation">;</span><span class="token property">background-color</span><span class="token punctuation">:</span><span class="token color hexcode">#272822</span><span class="token punctuation">;</span><span class="token property">-moz-tab-size</span><span class="token punctuation">:</span><span class="token number">4</span><span class="token punctuation">;</span><span class="token property">-o-tab-size</span><span class="token punctuation">:</span><span class="token number">4</span><span class="token punctuation">;</span><span class="token property">tab-size</span><span class="token punctuation">:</span><span class="token number">4</span></span><span class="token punctuation">&quot;</span></span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span> language-go<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>code</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span> language-go<span class="token punctuation">&quot;</span></span> <span class="token attr-name">data-lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>go<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token keyword<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>package<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> main </span><span class="code-line"> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token keyword<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>import<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token string<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>&quot;fmt&quot;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token keyword<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>func<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token function<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>main<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token punctuation<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>(<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token punctuation<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>)<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token punctuation<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> fmt </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token punctuation<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token function<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Println<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token punctuation<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>(<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token string<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>&quot;hello world&quot;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token punctuation<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>)<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>token punctuation<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>code</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>pre</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>hugo</p><div class="relative"><pre><code class="code-highlight language-html"><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>pre</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>chroma<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>code</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>language-go<span class="token punctuation">&quot;</span></span> <span class="token attr-name">data-lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>go<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>kn<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>package<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>nx<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>main<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>kn<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>import<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>s<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>&quot;fmt&quot;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>kd<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>func<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>nf<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>main<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>p<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>()<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>p<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>nx<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>fmt<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>p<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>nf<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Println<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>p<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>(<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>s<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>&quot;hello world&quot;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>p<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>)<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>p<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>code</span><span class="token punctuation">&gt;</span></span> </span><span class="code-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>pre</span><span class="token punctuation">&gt;</span></span> </span></code></pre></div><p>二者的解析引擎都是基于正则表达式的, 有错漏肯定是难免的。 看上去解析结果差不太多,不过貌似PrismJS 没有把 <code>fmt.Println</code> 调用里的 <code>fmt</code> 解析正确。 chroma的输出结果使用了更简短的class名称,看上去更精简一些。</p><p>最终我还是选定了hugo内置的高亮。放弃了前端方案。</p><p>内置的配色我感觉没有喜欢的,于是看看base64有没有chroma的配色,还真找到一个。</p><p>对于这个porting不太满意,因为它太多紫色的东西。 jetbrains 有一个 gruvbox theme自带的gruvbox color各方面都不错,我把它port过来了 <a href="https://github.com/ttys3/base16-chroma/blob/master/chroma-base16-css/cssvar/base16-gruvbox-dark-jb.css">https://github.com/ttys3/base16-chroma/blob/master/chroma-base16-css/cssvar/base16-gruvbox-dark-jb.css</a></p><p>最终形成我自己的fork: <a href="https://github.com/ttys3/base16-chroma">https://github.com/ttys3/base16-chroma</a></p><p>由于 base16 配色并不是专门为Chroma或Pygments设计的,因此,得把base16的 scheme 人肉转换到 Chroma 过来。</p><p>最终效果就是现在你看到的高亮效果。</p><p>这期间花了我不少时间,关于如何制作新的 base16 配色并应用于 hugo, 后续有空我再单独发文分享。</p><p>另外这个主题默认的<code>Fira Code</code>我给它换成<code>Jetbrains Mono</code> <a href="https://github.com/JetBrains/JetBrainsMono">https://github.com/JetBrains/JetBrainsMono</a> woff2字体,woff2体积几乎比woff小一半。 如果你查看兼容数据库 <a href="https://caniuse.com/#woff2">https://caniuse.com/#woff2</a> , 你会发现只有IE11 和 Opera Mini不支持。 所以,可以果断地用woff2了。</p><div><img alt="" src="https://ttys3.dev/static/assets/browser-woff2-compatible-table-2020-04-16-10-45-20-2GMDYZNL.png" width="2238" height="836"/></div><div><img alt="" src="https://ttys3.dev/static/assets/jetbrains-mono-font-woff2-2020-04-16-10-42-37-WI2YXLIV.png" width="1104" height="567"/></div><h2 id="内容组织"><a href="#内容组织" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>内容组织</h2><p>由于 hugo 不像 WP 这类有数据库的动态博客系统, hugo是生成静态页面的。</p><p>用目录来组织文章, markdown文件一般不会遇到问题,但是图片和其它附件呢?</p><p>如何有效的管理?方便写文章和修改,同时方便后期的查找和管理?</p><p>幸好,hugo 有一种叫 page bundle的模式。</p><p>就是一个页面下可以包含其它资源。</p><p>如果是一个叶节点页面bundle, 那么它下面可以放一个index.md 及 图片和其它附件。</p><p>比如我现在这个文章<code>deploy-hugo-blog-witn-container</code> 就是一个page bundle,文件结构如下:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">content/post/hugo/deploy-hugo-blog-witn-container </span><span class="code-line">├── cover-2020-04-16-03-50-14.png </span><span class="code-line">└── index.md </span></code></pre></div><p>这样的好处非常明显, 文章自己的图片放在文章自己的目录。</p><p>如果是公用的图片怎么办?放到 <code>static/img</code> 下面啊。</p><p>还有一个问题,在写文章的时候,怎么方便的在截图完成后,把图片存到当前目录并自动引入markdown中?</p><p>有一个神奇的 VS Code 插件叫Markdown Paste(<code>telesoho.vscode-markdown-paste-image</code>), 这个非常方便的功能就由它实现了。</p><p>用起来非常丝滑顺手。</p><p>剪切板中的图片,Ctrl+Alt+V 就能直接到markdown文件所在目录,并且自由粘贴markdown的图片代码。</p><p>这里主要是要感谢<a href="https://wrong.wang/blog/20190301-%E6%9C%AC%E7%AB%99%E5%BC%95%E7%94%A8%E5%9B%BE%E7%89%87%E7%9A%84%E9%A1%BA%E6%BB%91%E6%B5%81%E7%A8%8B/">王不对</a>, 如果没有看他的文章,我还一直不会去了解hugo的<a href="https://gohugo.io/content-management/page-bundles/">page bundle</a>这个功能。</p><p>当然,这是图片存在本服务器的情况,如果是用又拍云、七牛或者腾讯云COS做图床的话,VS Code里另外有其它的插件可以现实。</p><p>因为我是全站走CDN了,因此就懒得再弄CDN的图床了。</p><h2 id="配置"><a href="#配置" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>配置</h2><p>配置的话,采用最小化配置。 也就是,凡是hugo默认的配置,我们不写出来,我们只增加自己要修改的部分。</p><p>除了个单个config.toml配置,hugo还引入配置目录的功能。</p><p>每个顶层配置对象都拥有一个文件,如下图示:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line">├── config </span><span class="code-line">│ ├── _default </span><span class="code-line">│ │ ├── config.toml </span><span class="code-line">│ │ ├── languages.toml </span><span class="code-line">│ │ ├── menus.en.toml </span><span class="code-line">│ │ ├── menus.zh.toml </span><span class="code-line">│ │ └── params.toml </span><span class="code-line">│ ├── production </span><span class="code-line">│ │ ├── config.toml </span><span class="code-line">│ │ └── params.toml </span><span class="code-line">│ └── development </span><span class="code-line">│ ├── config.toml </span><span class="code-line">│ └── params.toml </span></code></pre></div><p>考虑到上述的结构,运行<code>hugo --environment development</code>时,hugo将读取<code>config/_default</code>的默认配置 然后和development合并。 也就是<code>_default</code>是默认配置,production 或 development 可以覆盖,也可以增加配置</p><blockquote><p>直接运行<code>hugo serve</code>时的默认环境是<code>development</code> 直接运行<code>hugo</code>时的默认环境是<code>production</code></p></blockquote><p>这样非常方便本地开发和部署到线上时切换不同的配置。</p><p>但是看了一下,官方的文档对于这个功能的描述非常的不清晰。 看了<a href="https://github.com/gohugoio/hugo/issues/5422">这个功能相关的issue</a> 大概了解了一些用法。 我想还是暂是不使用这个功能。</p><h2 id="评论系统"><a href="#评论系统" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>评论系统</h2><p>由于hugo是静态博客生成器,因此,我们要引入评论功能,只能通过API来嵌入评论。 hugo本身已经内置了Disqus,只需要配置一个id就能启用。</p><p>虽然国外的 Disqus评论系统其实还算好用,但是国内很无奈,主域名基本无法直接访问,然而它的js里也嵌入了api请求域名, 算起来差不多有三四个域名,所以,用反向代理我也嫌弃麻烦。放弃之。</p><p>国内的有changyan,也提供免费使用,但是肯定是不考虑的。原因不用多说。</p><p>基于gihtub的评论系统也有一些,比如gitment, gitalk等,但是我还是不想用这种,因为最近连github也是不能直接访问了。</p><p>还有个Valine是基于LeanCloud的服务的,这个我也不想用,用的什么对象存储,然后严重依赖LeanCloud这个国内的服务。 说是“无后端评论系统”,其实是把后端放在了LeanCloud。另外,这个新版本也要移除邮件提醒功能了, 需要邮件提醒还得再整一个第三方邮件提醒。</p><p>isso是基于py的,貌似很久没人维护了,这个也不满足条件。</p><p>go-isso实现还没完成,暂时也不是可用状态,继续找。</p><p>找到一个叫remark42的评论系统,这个评论系统啥都好,就是: 一,没有中文。二,不记录邮箱和网址。三,发邮件提醒只能用SMTP。 关于第一点,我已经提交了一个PR给官方,官方已经把中文语言merge进去了。关于第二点,基于隐私,不记录邮箱, 这个我可以理解,但是不记录网址,博客与博客之间就达不到那种互动互踩的效果了。其它博主在你的博客留言了,你却不知道他的博客网址。 不记录评论者网址这一点,我有时间再想办法改进一下。 第三点,我提交了一个使用sendgrid和mailgun的WEB API发邮件的PR给官方,然后官方拒绝了。 理由是“这会使代码膨胀”, 这是什么理由? 你集成了oauth登录功能,加了常见的github, google, twiiter,突然有一天你觉得yandex 也要加上了,然后你就把yandex也加上了,你的代码就不“膨胀”了?</p><p>为什么SMTP已经是“能用”状态了,带要用web api发送邮件?很简单,我都是用自己的VPS架设的博客,基于安全考虑,不希望SMTP协议暴露源站 IP。用WEB API可以很轻松地解决这个问题。</p><p>然后remark42官方提议,我另外弄一个side container跑一个SMTP到WEB API发送邮件的bridge服务。 然后,发邮件的流程就变成了:<code>remark42 =&gt; SMTP-WEB_API-bridge =&gt; SendGrid/Mailgun WEB API</code></p><p>问题是,明明可以通过代码解决了,再加个side container,至于么?</p><p>这是把开发者的责任,转架到了使用者身上。</p><p>并且,他拒绝我这个PR,然而他自己的oauth实现也是这样实现的。如果按照他这个逻辑,这个oauth登录功能也会使“代码膨胀”,</p><p>因为提供oauth登录服务的厂家永久在变动的。你们俄罗斯的用yandex, 到我们这了可能就要加别的厂家的登录接口功能了。</p><p>另外,我看了下他那个Dockerfile, 写得层数实在太多。我数了一下他最终生成的镜像层数,不多不少,正好17层。</p><p>一般我做镜像,基本上都会控制在10层以下,一般在5层左右。</p><p>因为docker用的是overlayfs, 一层一层覆盖的,层数越多,io效率越低。</p><p>那你可能会多,我层数多,加一个配置文件都是一个新层,方便更新啊。如果你要这样说的话,那我反问你, 做base image的人,是不是也要一个文件一个软件地加,给你弄个100层?方便你更新?</p><p>但是个人维护这么一个项目是极其要时间了,这也是为什么,我还是比较倾向于让官方接受我这个PR。</p><p>但是remark42的项目主负责人对于源站IP泄漏这种安全问题压根没有什么意识,在我的PR里他还反问我,大家的服务器都是public IP了, 这个IP本身就是公开的,还存在什么源站IP泄漏?我只能呵呵了。</p><p>我回了一句:你的服务器没有被DDos 攻击,你当然不会意识到这是一个问题。</p><p>最后,欢迎大家关注我的remark42 fork: <a href="https://github.com/ttys3/remark42/">https://github.com/ttys3/remark42/</a></p><p>同时也欢迎有兴趣的童鞋一起完善改进。</p><p>我现在使用的remark42是编译自我的fork的,然后通过github actions自动提交到了dockerhub:</p><p><a href="https://hub.docker.com/r/80x86/remark42">https://hub.docker.com/r/80x86/remark42</a></p><p>remark42部署效果图:</p><div><img alt="" src="https://ttys3.dev/static/assets/remark42-comment-form-2020-04-16-14-13-33-A6B74FT6.png" width="1716" height="918"/></div><h2 id="latex"><a href="#latex" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>LaTeX</h2><p>hugo目前的<code>goldmark</code>妈蛋解析引擎还不支持latex。 虽然结合katex js,实现一些简单的LaTeX解析是没问题的,但是如果LaTeX里有<code>_</code>和<code>[]</code> 这种妈蛋里也有的标记, 就会导致LaTeX的标记走丢了(被妈蛋抢走了)。</p><h2 id="容器部署"><a href="#容器部署" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>容器部署</h2><p>hugo产出的HTML直接用nginx容器跑http服务。 remark42容器提供评论API。 前端采用envoy做代理,hugo和remark42端口由envoy开放。</p><h3 id="nginx容器部署"><a href="#nginx容器部署" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>nginx容器部署</h3><p>一个基本的适用于hugo站点的nginx配置(<code>/etc/nginx/conf.d/default.conf</code>)如下:</p><div class="relative"><pre><code class="code-highlight language-nginx"><span class="code-line"><span class="token comment"># nginx config for hugo site</span> </span><span class="code-line"><span class="token comment"># author: ttys3</span> </span><span class="code-line"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">listen</span> <span class="token number">8080</span></span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">server_name</span> localhost</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment">#charset koi8-r;</span> </span><span class="code-line"> <span class="token comment">#access_log /var/log/nginx/host.access.log main;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">index</span> index.html</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token comment"># absolute_redirect must off for hugo site if no `$uri/index.html` on try_files</span> </span><span class="code-line"> <span class="token comment"># absolute_redirect off;</span> </span><span class="code-line"> <span class="token comment"># port_in_redirect off;</span> </span><span class="code-line"> <span class="token comment"># server_name_in_redirect off;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">root</span> /app/public</span><span class="token punctuation">;</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">try_files</span> <span class="token variable">$uri</span> <span class="token variable">$uri</span>/index.html =404</span><span class="token punctuation">;</span> <span class="token comment">#fixup for hugo</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"> </span><span class="code-line"> <span class="token comment"># redirect server error pages to the static page /50x.html</span> </span><span class="code-line"> <span class="token comment">#</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">error_page</span> <span class="token number">500</span> <span class="token number">502</span> <span class="token number">503</span> <span class="token number">504</span> /50x.html</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">location</span> = /50x.html</span> <span class="token punctuation">{</span> </span><span class="code-line"> <span class="token directive"><span class="token keyword">root</span> /usr/share/nginx/html</span><span class="token punctuation">;</span> </span><span class="code-line"> <span class="token punctuation">}</span> </span><span class="code-line"><span class="token punctuation">}</span> </span></code></pre></div><p>然后直接运行docker官方的nginx容器<code>nginx:1.17.9</code>,映射<code>/etc/nginx/conf.d/default.conf</code>配置文件,并映射/app/public目录:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">sudo</span> <span class="token function">docker</span> run <span class="token variable parameter">-d</span> <span class="token variable parameter">--name</span> hugo <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-v</span> hugo-public目录位置:/app/public:ro,z <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-v</span> default.conf文件位置:/etc/nginx/conf.d/default.conf:z <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">--mount</span> <span class="token variable assign-left">type</span><span class="token operator">=</span>tmpfs,destination<span class="token operator">=</span>/tmp <span class="token punctuation">\</span> </span><span class="code-line"> nginx:1.17.9 </span></code></pre></div><h3 id="remark42容器部署"><a href="#remark42容器部署" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>remark42容器部署</h3><p>怎么申请github, google, twitter的oauth登录接口,这里有详细的步骤: <a href="https://github.com/ttys3/remark42#register-oauth2-providers">https://github.com/ttys3/remark42#register-oauth2-providers</a></p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token function">sudo</span> <span class="token function">docker</span> run <span class="token variable parameter">-d</span> <span class="token variable parameter">--name</span> remark42 <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">REMARK_PORT</span><span class="token operator">=</span><span class="token number">8081</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">REMARK_URL</span><span class="token operator">=</span><span class="token string">&#x27;https://remark42的访问地址&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">PUID</span><span class="token operator">=</span><span class="token number">1000</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">TIME_ZONE</span><span class="token operator">=</span><span class="token string">&quot;Asia/Shanghai&quot;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">SITE</span><span class="token operator">=</span><span class="token string">&#x27;网站域名(不需要带http和端口)&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">ADMIN_SHARED_ID</span><span class="token operator">=</span><span class="token string">&#x27;管理员的用户id&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">ADMIN_SHARED_EMAIL</span><span class="token operator">=</span><span class="token string">&#x27;管理员邮件地址@example.com&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">ADMIN_PASSWD</span><span class="token operator">=</span><span class="token string">&#x27;管理员密码&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">SECRET</span><span class="token operator">=</span><span class="token string">&#x27;用于加密的密钥,自己随便md5一下弄个串出来放这就好了&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_EMAIL_ENABLE</span><span class="token operator">=</span>false <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_EMAIL_FROM</span><span class="token operator">=</span><span class="token string">&#x27;邮件认证或通知提醒时的发件人邮箱@sg.ttys3.net&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_GITHUB_CID</span><span class="token operator">=</span><span class="token string">&#x27;github-api-key填写这&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_GITHUB_CSEC</span><span class="token operator">=</span><span class="token string">&#x27;github-api-key-secret填写这&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_GOOGLE_CID</span><span class="token operator">=</span><span class="token string">&#x27;谷歌api-key填写这&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_GOOGLE_CSEC</span><span class="token operator">=</span><span class="token string">&#x27;谷歌api-key-secret填写这&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_TWITTER_CID</span><span class="token operator">=</span><span class="token string">&#x27;twitter-api-key填写这&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_TWITTER_CSEC</span><span class="token operator">=</span><span class="token string">&#x27;twitter-api-key-secret填写这&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">NOTIFY_TYPE</span><span class="token operator">=</span>email <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">AUTH_EMAIL_SUBJ</span><span class="token operator">=</span><span class="token string">&#x27;荒野無燈weblog登录确认&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">NOTIFY_EMAIL_VERIFICATION_SUBJ</span><span class="token operator">=</span><span class="token string">&#x27;确认订阅来自荒野無燈weblog的评论&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">NOTIFY_EMAIL_ADMIN</span><span class="token operator">=</span>true <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">EMAIL_PROVIDER</span><span class="token operator">=</span>sendgrid <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">EMAIL_SG_API_KEY</span><span class="token operator">=</span><span class="token string">&#x27;你的sendgrid密钥填这&#x27;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-e</span> <span class="token variable assign-left">EMOJI</span><span class="token operator">=</span>true <span class="token punctuation">\</span> </span><span class="code-line"><span class="token variable parameter">-v</span> /home/data/remark42:/srv/var:rw,z <span class="token punctuation">\</span> </span><span class="code-line">80x86/remark42:latest </span></code></pre></div><p>AUTH_GITHUB_CID / AUTH_GITHUB_CID 这几个不是必须的。 比如你只想启用github登录评论,则只需要配置<code>AUTH_GITHUB_CID</code> 和 <code>AUTH_GITHUB_CSEC</code>。 目前我实现了mailgun和sendgrid这两个发送邮件的provider, 如果你用mailgun,请修改上面的 <code>EMAIL_PROVIDER=sendgrid</code>为 <code>EMAIL_PROVIDER=mailgun</code></p><p>更多配置信息请去 <a href="https://github.com/ttys3/remark42">https://github.com/ttys3/remark42</a> 查看。</p><h3 id="envoy容器部署"><a href="#envoy容器部署" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>envoy容器部署</h3><p><a href="https://www.servicemesher.com/envoy/intro/what_is_envoy.html">Envoy 是什么?</a></p><blockquote><p>Envoy 是专为大型现代 SOA(面向服务架构)架构设计的 L7 代理和通信总线。</p></blockquote><p>Envoy Proxy 在代理方面性能咋样呢?老灯这里放两张2018年的图(<a href="https://www.loggly.com/blog/benchmarking-5-popular-load-balancers-nginx-haproxy-envoy-traefik-and-alb/">来源</a>):</p><div><img alt="" src="https://ttys3.dev/static/assets/envoy-bench-http-2020-04-16-13-42-08-6CPPDQI5.png" width="680" height="451"/></div><div><img alt="" src="https://ttys3.dev/static/assets/envoy-bench-https-2020-04-16-13-42-23-HIEGIIZG.png" width="680" height="451"/></div><p>Envoy Proxy 主要是用来在微服务架构中做service mesh的, 但是这里我们用它来做edge proxy对它来说当然更是小菜一碟。</p><p>关于做edge proxy的例子,官方的最佳实践文档中有: <a href="https://www.envoyproxy.io/docs/envoy/latest/configuration/best_practices/edge">Configuring Envoy as an edge proxy</a></p><p>这里老灯分享上我的配置<code>envoy.yaml</code>:</p><div class="relative"><pre><code class="code-highlight language-yml"><span class="code-line"><span class="token comment"># https://www.envoyproxy.io/docs/envoy/latest/configuration/best_practices/edge</span> </span><span class="code-line"><span class="token atrule key">overload_manager</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">refresh_interval</span><span class="token punctuation">:</span> 0.25s </span><span class="code-line"> <span class="token atrule key">resource_monitors</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;envoy.resource_monitors.fixed_heap&quot;</span> </span><span class="code-line"> <span class="token atrule key">typed_config</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">&quot;@type&quot;</span><span class="token punctuation">:</span> type.googleapis.com/envoy.config.resource_monitor.fixed_heap.v2alpha.FixedHeapConfig </span><span class="code-line"> <span class="token comment"># TODO: Tune for your system.</span> </span><span class="code-line"> <span class="token atrule key">max_heap_size_bytes</span><span class="token punctuation">:</span> <span class="token number">2147483648</span> <span class="token comment"># 2 GiB</span> </span><span class="code-line"> <span class="token atrule key">actions</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;envoy.overload_actions.shrink_heap&quot;</span> </span><span class="code-line"> <span class="token atrule key">triggers</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;envoy.resource_monitors.fixed_heap&quot;</span> </span><span class="code-line"> <span class="token atrule key">threshold</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">value</span><span class="token punctuation">:</span> <span class="token number">0.95</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;envoy.overload_actions.stop_accepting_requests&quot;</span> </span><span class="code-line"> <span class="token atrule key">triggers</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> <span class="token string">&quot;envoy.resource_monitors.fixed_heap&quot;</span> </span><span class="code-line"> <span class="token atrule key">threshold</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">value</span><span class="token punctuation">:</span> <span class="token number">0.98</span> </span><span class="code-line"> </span><span class="code-line"><span class="token atrule key">admin</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">access_log_path</span><span class="token punctuation">:</span> <span class="token string">&quot;/dev/null&quot;</span> </span><span class="code-line"> <span class="token atrule key">address</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">socket_address</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">address</span><span class="token punctuation">:</span> 0.0.0.0 </span><span class="code-line"> <span class="token atrule key">port_value</span><span class="token punctuation">:</span> <span class="token number">9901</span> </span><span class="code-line"> </span><span class="code-line"><span class="token atrule key">static_resources</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">listeners</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">address</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">socket_address</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">address</span><span class="token punctuation">:</span> 0.0.0.0 </span><span class="code-line"> <span class="token atrule key">port_value</span><span class="token punctuation">:</span> <span class="token number">80</span> </span><span class="code-line"> <span class="token atrule key">per_connection_buffer_limit_bytes</span><span class="token punctuation">:</span> <span class="token number">32768</span> <span class="token comment"># 32 KiB</span> </span><span class="code-line"> <span class="token atrule key">filter_chains</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">filters</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> envoy.filters.network.http_connection_manager </span><span class="code-line"> <span class="token atrule key">typed_config</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">&quot;@type&quot;</span><span class="token punctuation">:</span> type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager </span><span class="code-line"> <span class="token atrule key">stat_prefix</span><span class="token punctuation">:</span> ingress_http </span><span class="code-line"> <span class="token atrule key">use_remote_address</span><span class="token punctuation">:</span> <span class="token important boolean">true</span> </span><span class="code-line"> <span class="token atrule key">common_http_protocol_options</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">idle_timeout</span><span class="token punctuation">:</span> 3600s <span class="token comment"># 1 hour</span> </span><span class="code-line"> <span class="token atrule key">http2_protocol_options</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">max_concurrent_streams</span><span class="token punctuation">:</span> <span class="token number">100</span> </span><span class="code-line"> <span class="token atrule key">initial_stream_window_size</span><span class="token punctuation">:</span> <span class="token number">65536</span> <span class="token comment"># 64 KiB</span> </span><span class="code-line"> <span class="token atrule key">initial_connection_window_size</span><span class="token punctuation">:</span> <span class="token number">1048576</span> <span class="token comment"># 1 MiB</span> </span><span class="code-line"> <span class="token atrule key">stream_idle_timeout</span><span class="token punctuation">:</span> 60s <span class="token comment"># 1 mins, must be disabled for long-lived and streaming requests</span> </span><span class="code-line"> <span class="token atrule key">request_timeout</span><span class="token punctuation">:</span> 60s <span class="token comment"># 1 mins, must be disabled for long-lived and streaming requests</span> </span><span class="code-line"> <span class="token atrule key">access_log</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> envoy.file_access_log </span><span class="code-line"> <span class="token atrule key">config</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">path</span><span class="token punctuation">:</span> <span class="token string">&quot;/dev/stderr&quot;</span> </span><span class="code-line"> <span class="token atrule key">route_config</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">virtual_hosts</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> comment </span><span class="code-line"> <span class="token atrule key">domains</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token string">&quot;cmt.ttys3.net&quot;</span> </span><span class="code-line"> <span class="token atrule key">routes</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">match</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token atrule key">prefix</span><span class="token punctuation">:</span> <span class="token string">&quot;/&quot;</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">route</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">cluster</span><span class="token punctuation">:</span> service_comment </span><span class="code-line"> <span class="token atrule key">idle_timeout</span><span class="token punctuation">:</span> 15s <span class="token comment"># must be disabled for long-lived and streaming requests</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> hugo </span><span class="code-line"> <span class="token atrule key">domains</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token string">&quot;ttys3.net&quot;</span> </span><span class="code-line"> <span class="token atrule key">routes</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">match</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token atrule key">prefix</span><span class="token punctuation">:</span> <span class="token string">&quot;/&quot;</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">route</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">cluster</span><span class="token punctuation">:</span> service_hugo </span><span class="code-line"> <span class="token atrule key">idle_timeout</span><span class="token punctuation">:</span> 15s <span class="token comment"># must be disabled for long-lived and streaming requests</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> cgit </span><span class="code-line"> <span class="token atrule key">domains</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token string">&quot;git.ttys3.net&quot;</span> </span><span class="code-line"> <span class="token atrule key">routes</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">match</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token atrule key">prefix</span><span class="token punctuation">:</span> <span class="token string">&quot;/&quot;</span> <span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">route</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">cluster</span><span class="token punctuation">:</span> service_cgit </span><span class="code-line"> <span class="token atrule key">idle_timeout</span><span class="token punctuation">:</span> 15s <span class="token comment"># must be disabled for long-lived and streaming requests</span> </span><span class="code-line"> <span class="token comment"># hugo nginx only listen on http</span> </span><span class="code-line"> <span class="token atrule key">http_filters</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> envoy.router </span><span class="code-line"> <span class="token atrule key">config</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> </span><span class="code-line"> <span class="token atrule key">clusters</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> service_hugo </span><span class="code-line"> <span class="token atrule key">connect_timeout</span><span class="token punctuation">:</span> 3s </span><span class="code-line"> <span class="token atrule key">per_connection_buffer_limit_bytes</span><span class="token punctuation">:</span> <span class="token number">32768</span> <span class="token comment"># 32 KiB</span> </span><span class="code-line"> <span class="token atrule key">lb_policy</span><span class="token punctuation">:</span> round_robin </span><span class="code-line"> <span class="token atrule key">type</span><span class="token punctuation">:</span> <span class="token string">&quot;STRICT_DNS&quot;</span> </span><span class="code-line"> <span class="token atrule key">hosts</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">socket_address</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">address</span><span class="token punctuation">:</span> hugo </span><span class="code-line"> <span class="token atrule key">port_value</span><span class="token punctuation">:</span> <span class="token number">8080</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> service_comment </span><span class="code-line"> <span class="token atrule key">connect_timeout</span><span class="token punctuation">:</span> 3s </span><span class="code-line"> <span class="token atrule key">per_connection_buffer_limit_bytes</span><span class="token punctuation">:</span> <span class="token number">32768</span> <span class="token comment"># 32 KiB</span> </span><span class="code-line"> <span class="token atrule key">lb_policy</span><span class="token punctuation">:</span> round_robin </span><span class="code-line"> <span class="token atrule key">type</span><span class="token punctuation">:</span> <span class="token string">&quot;STRICT_DNS&quot;</span> </span><span class="code-line"> <span class="token atrule key">hosts</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">socket_address</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">address</span><span class="token punctuation">:</span> remark42 </span><span class="code-line"> <span class="token atrule key">port_value</span><span class="token punctuation">:</span> <span class="token number">8081</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">name</span><span class="token punctuation">:</span> service_cgit </span><span class="code-line"> <span class="token atrule key">connect_timeout</span><span class="token punctuation">:</span> 3s </span><span class="code-line"> <span class="token atrule key">per_connection_buffer_limit_bytes</span><span class="token punctuation">:</span> <span class="token number">32768</span> <span class="token comment"># 32 KiB</span> </span><span class="code-line"> <span class="token atrule key">lb_policy</span><span class="token punctuation">:</span> round_robin </span><span class="code-line"> <span class="token atrule key">type</span><span class="token punctuation">:</span> <span class="token string">&quot;STRICT_DNS&quot;</span> </span><span class="code-line"> <span class="token atrule key">hosts</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token punctuation">-</span> <span class="token atrule key">socket_address</span><span class="token punctuation">:</span> </span><span class="code-line"> <span class="token atrule key">address</span><span class="token punctuation">:</span> cgit </span><span class="code-line"> <span class="token atrule key">port_value</span><span class="token punctuation">:</span> <span class="token number">8082</span> </span></code></pre></div><p>注意:</p><blockquote><p>Envoy Proxy的配置文件是YAML格式,注意要用空格,不要用tab. docker的DNS服务会自动把容器名称映射到容器的IP地址,因此clusters配置这里的<code>address: hugo</code>要与前面创建的hugo容器名称<code>hugo</code>对应。</p></blockquote><p>这里老灯开了3个服务,一个hugo, 一个comment, 一个cgit. 我在创建容器的时候,分别让hugo监听8080, remark42 comment监听 8081, cgit 监听8082端口。</p><ul><li>hugo使用域名:<code>ttys3.net</code></li><li>评论使用域名:<code>cmt.ttys3.net</code></li><li>cgit使用域名:<code>git.ttys3.net</code> (暂未架设,预留)</li></ul><p>然后为了简单起见,我们只让Envoy Proxy对外暴露出80端口,因此我这里也没有配置SSL。 为什么呢?因为通过走cloudflare CDN之后,CF可以自动提供SSL证书。 如果要弄SSL,咱也可以直接弄个自签名的SSL就行了,因为 CF 也认。 或者,讲究一点,弄个ACME自动证书。</p><p>这里开放的9901 端口是用于查询一些Envoy Proxy的状态的,注意这个端口是不需要认证就能访问的,因此用容器跑的时候, 一般不要绑定到<code>0.0.0.0</code>让外网能访问到。 因为通过这个WEB接口是能关掉Envoy Proxy,甚至能修改配置的。</p><div><img alt="" src="https://ttys3.dev/static/assets/envoy-admin-web-ui-2020-04-16-13-56-45-YRZVPVZ5.png" width="1548" height="1756"/></div><p>运行Envoy Proxy容器:</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"> <span class="token function">sudo</span> <span class="token function">docker</span> run <span class="token variable parameter">-d</span> <span class="token variable parameter">--name</span> envoy <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-v</span> envoy.yaml文件的绝对路径:/etc/envoy/envoy.yaml:z,ro <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-p</span> <span class="token number">127.0</span>.0.1:9901:9901 <span class="token punctuation">\</span> </span><span class="code-line"> <span class="token variable parameter">-p</span> <span class="token number">80</span>:80 <span class="token punctuation">\</span> </span><span class="code-line"> envoyproxy/envoy:v1.14.1 </span></code></pre></div><p>这里我们只开放了80端口,如果启用了SSL, 需要加上<code>-p 443:443 \</code></p><h3 id="podman注意事项"><a href="#podman注意事项" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>podman注意事项</h3><p>由于老灯目前是在用podman,没有用docker, 也就是以上命令里的docker替换成podman就能跑了。</p><p>使用docker的注意以上运行容器的命令都要加上<code>--restart=unless-stopped</code>, 不然机器重启后容器不会自动启动。</p><p>使用podman的则要使用<code>podman generate systemd 容器id或名称</code> 来生成systemd unit文件并启用服务来实现开机自启。</p><h2 id="其它"><a href="#其它" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它</h2><p>Envoy Proxy容器可不可以用nginx做基于域名的虚拟主机来做反向代理替换掉? 完全可以。</p><h3 id="hugo-public目录发布的问题"><a href="#hugo-public目录发布的问题" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>hugo public目录发布的问题</h3><p>我暂时用了最简单的方法,直接一个<code>up.sh</code>脚本完事</p><div class="relative"><pre><code class="code-highlight language-shell"><span class="code-line"><span class="token important shebang">#!/bin/sh</span> </span><span class="code-line"> </span><span class="code-line"><span class="token function">env</span> <span class="token variable assign-left">TZ</span><span class="token operator">=</span><span class="token string">&#x27;Asia/Shanghai&#x27;</span> hugo <span class="token variable parameter">--gc</span> <span class="token variable parameter">--minify</span> <span class="token variable parameter">--enableGitInfo</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">\</span> </span><span class="code-line"><span class="token function">rsync</span> <span class="token variable parameter">-ravz</span> <span class="token variable parameter">--progress</span> <span class="token variable parameter">--checksum</span> <span class="token variable parameter">--delete</span> public/ root@服务器地址:/home/http/html/ttys3.net </span></code></pre></div><p>这里的<code>/home/http/html/ttys3.net</code> 就是hugo网站的根目录了。</p><p>也可以采用在服务端架设gitolite,然后用git hook实现自动发布hugo站点,这个后续有时间再分享。</p><h3 id="其它部署方式"><a href="#其它部署方式" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>其它部署方式?</h3><p>hugo支持很多部署方式,包括直接托管在<a href="https://gohugo.io/hosting-and-deployment/hosting-on-github/">github pages</a> 或者用Github Actions实现自动化部署Hugo博客, 以及托管在<a href="https://gohugo.io/hosting-and-deployment/hosting-on-netlify/">netlify</a>. 更多部署方式可以在<a href="https://gohugo.io/hosting-and-deployment/">hugo官网</a>找到。</p><h3 id="邮件发送api的选择"><a href="#邮件发送api的选择" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>邮件发送API的选择</h3><p>Mailgun和SendGrid都提供免费的plan,默认情况下,Mailgun每月的发送量送得更多(限制1万封)。 SendGrid在试用期过后,每天的邮件数量会限制在100封,感觉可用性不是很高。</p><blockquote><p>Mailgun(<a href="https://www.mailgun.com/">https://www.mailgun.com/</a>) Free Plan provides 10,000 Emails per month</p></blockquote><blockquote><p>SendGrid(<a href="https://sendgrid.com">https://sendgrid.com</a>) Trial Plan provides 40,000 emails for 30 days. After your trial ends, you can send 100 emails/day for free</p></blockquote><h3 id="优秀的hugo主题推荐"><a href="#优秀的hugo主题推荐" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>优秀的hugo主题推荐</h3><p>浅色系:</p><p><a href="https://github.com/olOwOlo/hugo-theme-even">https://github.com/olOwOlo/hugo-theme-even</a></p><p><a href="https://github.com/xianmin/hugo-theme-jane">https://github.com/xianmin/hugo-theme-jane</a></p><p><a href="https://github.com/zhengzangw/hugo-theme-ztyblog">https://github.com/zhengzangw/hugo-theme-ztyblog</a></p><p>暗黑系:</p><p><a href="https://github.com/panr/hugo-theme-hello-friend">https://github.com/panr/hugo-theme-hello-friend</a></p><p>hello-friend的第三方fork版: <a href="https://github.com/rhazdon/hugo-theme-hello-friend-ng">https://github.com/rhazdon/hugo-theme-hello-friend-ng</a></p><p>更多主题请去 <a href="https://themes.gohugo.io/">https://themes.gohugo.io/</a> 查看。</p><h3 id="hugo基础教程"><a href="#hugo基础教程" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>hugo基础教程?</h3><p>Hugo 从入门到会用 <a href="https://blog.olowolo.com/post/hugo-quick-start/">https://blog.olowolo.com/post/hugo-quick-start/</a></p><p>博客迁移——Hugo使用整体概览 <a href="https://www.rectcircle.cn/posts/blog-migration/">https://www.rectcircle.cn/posts/blog-migration/</a></p><h3 id="todo"><a href="#todo" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>TODO</h3><ul><li>站内搜索功能</li><li>友情链接页面</li></ul> Tue, 14 Apr 2020 17:17:08 GMT ttyS3 hugodockerpodmancontainernginxenvoy https://ttys3.dev/blog/new-blog-new-domain 新博客、新域名 -- hugo个人博客折腾记之前篇 https://ttys3.dev/blog/new-blog-new-domain <h2 id="回顾博客折腾之路"><a href="#回顾博客折腾之路" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>回顾博客折腾之路</h2><p>博客圈子里熟悉无灯的童鞋可能知道, 老灯早期玩了相当长一段时间的 <strong>WordPress</strong>. 后面又折腾过Habari(已经阵亡) 和 typecho, 后面换成了自己基于Kohana(2016年停止更新)写的博客系统,再后来又换成了自己基于Yii2框架写的博客系统. 可能是嫌弃自己写的博客系统体验太差了吧,正好给了借口可以不写博客了. 因此博客从刚开始的日更周更,变成月更,渐渐地变成了季更,年更,最后变成了长期不更了.</p><p>博客域名刚开始是<code>ihacklog.com</code>(停止续费,丢弃), 后面切换成<code>80x86.io</code>(停止续费,丢弃),而现在的域名是<code>ttys3.net</code>,原因很简单,不同时间,折腾的东西不同,喜好也会产生变化,因此域名命名上也会变化。</p><p>早期一起折腾WP的像万戈(现在没找到了,可能不存在了)和<a href="https://immmmm.com/">木木</a>, 比如万戈牌工具条在圈子里当时挺火的,木木则主要偏重主题方面的折腾。 我当时也是各种魔改主题和插件, 也写了一些自己的插件.</p><p>其实早就想把博客重新整一整, 但是越是对这些博客系统了解越多,选择反而更纠结了。 是用WP呢?还是用Drupal呢?或者是用基于Symfony 4框架的<a href="https://github.com/bolt/core">bolt</a> 呢?</p><h2 id="重新思考"><a href="#重新思考" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>重新思考</h2><p>怎么选?分析一下自己的核心需求吧:</p><ul><li>支持markdown</li><li>支持代码高亮</li><li>支持发图片和附件</li></ul><p>这个需求很简单啊。WP的插件系统固然非常灵活,但是官方编辑器默认是WYSIWYG(所见即所得)的. 这显然跟我的需求不太符合. 自从新版本的WordPress编辑器更换为<a href="https://wordpress.org/gutenberg/">Gutenberg</a>之后,我就再也没有用它的想法了.写几个文字还要一直点点点,选择这一个块是代码,是图片,还是视频?这是什么操作?当然,不能接受这个新编辑器的也不只老灯一人,很多重度使用者都采用hack方法,切换回了经典编辑器. 官方当然也知道大家的想法,弄了个插件以支持这些切换回旧编辑器的用户。但是我想说的是,官方既然已经决定了用Gutenberg,旧版编辑器彻底被干掉也只是时间的问题。WP不是一个有创新的产品,都2020年了,bitbucket都要移除hg支持了,而向WP官方插件仓库提交代码还只能使用svn。我想这也可以理解,一个生态已经好了,如果从svn换成git可能会导致很多插件失去维护,这可能是官方最担心的。</p><p>Drupal呢? 相对于WP来说,它的市场份额可能是很少的,但是相对于其它博客系统来说,它仍然算是占比较大的。Drupal的问题正好跟WP相反。相比于WP万年不变的svn, 新版本的Drupal已经在使用流行的Symfony框架和composer包管理了。但是Drupal的问题也很明显,每个大版本之间的兼容性很差,而新版本推出了,还在大量的用户因为插件依赖或技术问题无法升级或者不愿意升级到新版本。Drupal 9都快出来了,但是还有大把人在用7. 我试用了一下Drupal 8, 直接用的官方的docker镜像跑的,非常顺利。Drupal不是一个简单的CMS,而是一个框架级的CMF。 所以,我问了下自己,我写个博客真的需要用上Drupal吗?</p><p>Typecho是个非常小巧,运行效率极高的博客系统,深得一些嫌弃WP太重的用户欢心。我个人非常不喜欢它那个markdown编辑器,链接和图片等markdown语法它用的是“参考式链接的写法”,一个好好的链接,在Typecho编辑器里一添加, 变成了<code>[标题][3]</code>这样的玩意,然后<code>[3]</code>具体表示的是什么你还得去文章最底部找半天。这一点我完全无法接受。Typecho默认上传的附件无论是图片和附件,都是随机命名,没错,随机,这些文件名一旦脱离了Typecho这个系统,单看文件名,连哪张图片在前哪张在后你都搞不清楚。(我说的是系统本身的设计,并不涉及插件,事实上,只要你会代码,你改什么程序的代码不能改?)其它方面比如插件系统,主题系统它该有的都有。但是代码基本上处于无人维护的状态。最近一个公开正式发行的版本为0.9版(2013-12-12), 虽然github上目前还有些小修改,但是核心作者的精力在别的地方了,基本上不太可能有时间维护这个项目。</p><p>基于Symfony 4框架的<a href="https://github.com/bolt/core">bolt</a> 呢?这个博客系统的第4版还在RC阶段,不过发布应该快了。默认是WYSIWYG编辑器,但是可以通过配置切换成markdown编辑器。后台有一些奇怪的设计,我体验过后发现使用上有些不太习惯或者说难以接受。 另外bolt4不是使用了基于AR(Active Record, 比如Laravel的Eloquent)模式的东西,而是基于ORM的Doctrine, Doctrine这个块头有点大了,对于一个小博客来说.</p><p>然后呢?这些就是你不用这些系统的理由? 算是,也不算是。</p><p>我就是写几行字,我用得着架设一个PHP,还要架设一个NGINX, 然后还要架一个MySQL server么? 对于简单地写作需求来说,这些基于PHP的系统部署起来都太麻烦了,而且,部署好了还需要维护。</p><h2 id="新的决定"><a href="#新的决定" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>新的决定</h2><p>最终我决定以程序员的方式来写博客,那就是</p><div class="relative"><pre><code class="language-js code-highlight"><span class="code-line"><span class="token maybe-class-name">Git</span> <span class="token operator">+</span> markdown </span></code></pre></div><p>Git仓库用来保存markdown文档,那么markdown怎么转换成html的博客呢? 这类静态站点生成器很多,基于node.js开发的有<a href="https://hexo.io/">hexo</a>, 基于React的有<a href="https://www.gatsbyjs.org/">Gatsby</a>, 基于Golang的有<a href="https://gohugo.io/">hugo</a>.</p><p>hexo一般前端人员比较偏爱,也正是由于它的用户的群体,它的主题和插件数量应当会相当丰富。Gatsby更灵活,相对来说上手难度更高了。hugo 是最方便的,直接下载一个可执行文件hugo就好了,没有任何依赖。</p><p>根据<a href="https://gohugo.io/news/0.68.0-relnotes/">Hugo 0.68.0的发布说明</a>, Hugo现在有</p><ul><li>42462+ stars (四万以上的星星)</li><li>439+ contributors (四百以上的贡献者)</li><li>300+ themes (三百个以上的<a href="https://themes.gohugo.io">主题</a>)</li></ul><p>然后我看了下,<a href="https://hexo.io/themes/">hexo官方主题</a>也才300个左右.</p><p>所以,总体来说,使用Hugo的情况还算比较乐观。特别是官方发版特别勤快,bug修复及时。</p><p>好了,程序选好了,主题呢?我在逛<a href="https://immmmm.com/">木木</a>的博客时发现他那个主题特别好看。从footer找到了主题作者的github, 发现了同作者的另一款主题<a href="https://github.com/panr/hugo-theme-terminal">terminal</a>, 这个主题名字深得我心啊。<code>terminal</code>跟 <code>ttyS3.net</code> 这个域名是绝配啊。 虽然很想偷懒把木木那个主题直接拿来用, 但是最终还是决定用先用一下<code>terminal</code>吧。</p><p>根据自己的需求,对这个主题做了一些小调整,同样喜欢这个主题的可以关注一下我的fork: <a href="https://github.com/ttys3/hugo-theme-terminal/tree/ttys3">https://github.com/ttys3/hugo-theme-terminal/tree/ttys3</a></p><p>这个主题支持5各配色方案自由切换 <code>[&quot;orange&quot;, &quot;blue&quot;, &quot;red&quot;, &quot;green&quot;, &quot;pink&quot;]</code></p><p>唯一奇怪的地方是默认居左,这在4K屏下,整个右半边都是空的。不过还好作者有提供选项调整, 设置<code>centerTheme = true</code> 即可,另外还有<code>fullWidthTheme</code>选项,我个人不是很喜欢网页弄成全屏宽,毕竟咱人的眼睛又不是鱼眼,看不了那么宽。</p><p>之前博客的内容去哪儿了?由于旧网站是部署在linode jp节点上的,现在这个node已经直接删除了,数据库和文件我进行了打包备份, 里面可能有一些东西是有用的,但是目前来说还没空整理。 现在之所以重新开始,也是想没有历史的包袱,一切从简。</p><p>好了,这篇就写到这里了,关于架设这个博客的技术细节,请看下回分解。</p> Tue, 07 Apr 2020 15:55:53 GMT ttyS3 hugo https://ttys3.dev/blog/the-time-machine The Time Machine https://ttys3.dev/blog/the-time-machine <h1 id="the-time-machine-by-h-g-wells"><a href="#the-time-machine-by-h-g-wells" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>The Time Machine by H. G. Wells</h1><p><em>Title</em>: The Time Machine</p><p><em>Author</em>: H. G. Wells</p><p><em>Subject</em>: Science Fiction</p><p><em>Language</em>: English</p><p><em>Source</em>: <a href="https://www.gutenberg.org/ebooks/35">Project Gutenberg</a></p><h2 id="introduction"><a href="#introduction" aria-hidden="true" tabindex="-1"><span class="icon icon-link"></span></a>Introduction</h2><p>The Time Traveller (for so it will be convenient to speak of him) was expounding a recondite matter to us. His pale grey eyes shone and twinkled, and his usually pale face was flushed and animated. The fire burnt brightly, and the soft radiance of the incandescent lights in the lilies of silver caught the bubbles that flashed and passed in our glasses. Our chairs, being his patents, embraced and caressed us rather than submitted to be sat upon, and there was that luxurious after-dinner atmosphere, when thought runs gracefully free of the trammels of precision. And he put it to us in this way—marking the points with a lean forefinger—as we sat and lazily admired his earnestness over this new paradox (as we thought it) and his fecundity.</p><p>“You must follow me carefully. I shall have to controvert one or two ideas that are almost universally accepted. The geometry, for instance, they taught you at school is founded on a misconception.”</p><p>“Is not that rather a large thing to expect us to begin upon?” said Filby, an argumentative person with red hair.</p><p>“I do not mean to ask you to accept anything without reasonable ground for it. You will soon admit as much as I need from you. You know of course that a mathematical line, a line of thickness <em>nil</em>, has no real existence. They taught you that? Neither has a mathematical plane. These things are mere abstractions.”</p><p>“That is all right,” said the Psychologist.</p><p>“Nor, having only length, breadth, and thickness, can a cube have a real existence.”</p><p>“There I object,” said Filby. “Of course a solid body may exist. All real things—”</p><p>“So most people think. But wait a moment. Can an <em>instantaneous</em> cube exist?”</p><p>“Don’t follow you,” said Filby.</p><p>“Can a cube that does not last for any time at all, have a real existence?”</p><p>Filby became pensive. “Clearly,” the Time Traveller proceeded, “any real body must have extension in <em>four</em> directions: it must have Length, Breadth, Thickness, and—Duration. But through a natural infirmity of the flesh, which I will explain to you in a moment, we incline to overlook this fact. There are really four dimensions, three which we call the three planes of Space, and a fourth, Time. There is, however, a tendency to draw an unreal distinction between the former three dimensions and the latter, because it happens that our consciousness moves intermittently in one direction along the latter from the beginning to the end of our lives.”</p><p>“That,” said a very young man, making spasmodic efforts to relight his cigar over the lamp; “that . . . very clear indeed.”</p><p>“Now, it is very remarkable that this is so extensively overlooked,” continued the Time Traveller, with a slight accession of cheerfulness. “Really this is what is meant by the Fourth Dimension, though some people who talk about the Fourth Dimension do not know they mean it. It is only another way of looking at Time. <em>There is no difference between Time and any of the three dimensions of Space except that our consciousness moves along it</em>. But some foolish people have got hold of the wrong side of that idea. You have all heard what they have to say about this Fourth Dimension?”</p><p>“<em>I</em> have not,” said the Provincial Mayor.</p><p>“It is simply this. That Space, as our mathematicians have it, is spoken of as having three dimensions, which one may call Length, Breadth, and Thickness, and is always definable by reference to three planes, each at right angles to the others. But some philosophical people have been asking why <em>three</em> dimensions particularly—why not another direction at right angles to the other three?—and have even tried to construct a Four-Dimensional geometry. Professor Simon Newcomb was expounding this to the New York Mathematical Society only a month or so ago. You know how on a flat surface, which has only two dimensions, we can represent a figure of a three-dimensional solid, and similarly they think that by models of three dimensions they could represent one of four—if they could master the perspective of the thing. See?”</p><p>“I think so,” murmured the Provincial Mayor; and, knitting his brows, he lapsed into an introspective state, his lips moving as one who repeats mystic words. “Yes, I think I see it now,” he said after some time, brightening in a quite transitory manner.</p><p>“Well, I do not mind telling you I have been at work upon this geometry of Four Dimensions for some time. Some of my results are curious. For instance, here is a portrait of a man at eight years old, another at fifteen, another at seventeen, another at twenty-three, and so on. All these are evidently sections, as it were, Three-Dimensional representations of his Four-Dimensioned being, which is a fixed and unalterable thing.</p><p>“Scientific people,” proceeded the Time Traveller, after the pause required for the proper assimilation of this, “know very well that Time is only a kind of Space. Here is a popular scientific diagram, a weather record. This line I trace with my finger shows the movement of the barometer. Yesterday it was so high, yesterday night it fell, then this morning it rose again, and so gently upward to here. Surely the mercury did not trace this line in any of the dimensions of Space generally recognised? But certainly it traced such a line, and that line, therefore, we must conclude, was along the Time-Dimension.”</p><p>“But,” said the Medical Man, staring hard at a coal in the fire, “if Time is really only a fourth dimension of Space, why is it, and why has it always been, regarded as something different? And why cannot we move in Time as we move about in the other dimensions of Space?”</p><p>The Time Traveller smiled. “Are you so sure we can move freely in Space? Right and left we can go, backward and forward freely enough, and men always have done so. I admit we move freely in two dimensions. But how about up and down? Gravitation limits us there.”</p><p>“Not exactly,” said the Medical Man. “There are balloons.”</p><p>“But before the balloons, save for spasmodic jumping and the inequalities of the surface, man had no freedom of vertical movement.”</p><p>“Still they could move a little up and down,” said the Medical Man.</p><p>“Easier, far easier down than up.”</p><p>“And you cannot move at all in Time, you cannot get away from the present moment.”</p><p>“My dear sir, that is just where you are wrong. That is just where the whole world has gone wrong. We are always getting away from the present moment. Our mental existences, which are immaterial and have no dimensions, are passing along the Time-Dimension with a uniform velocity from the cradle to the grave. Just as we should travel <em>down</em> if we began our existence fifty miles above the earth’s surface.”</p><p>“But the great difficulty is this,” interrupted the Psychologist. ’You <em>can</em> move about in all directions of Space, but you cannot move about in Time.”</p><p>“That is the germ of my great discovery. But you are wrong to say that we cannot move about in Time. For instance, if I am recalling an incident very vividly I go back to the instant of its occurrence: I become absent-minded, as you say. I jump back for a moment. Of course we have no means of staying back for any length of Time, any more than a savage or an animal has of staying six feet above the ground. But a civilised man is better off than the savage in this respect. He can go up against gravitation in a balloon, and why should he not hope that ultimately he may be able to stop or accelerate his drift along the Time-Dimension, or even turn about and travel the other way?”</p><p>“Oh, <em>this</em>,” began Filby, “is all—”</p><p>“Why not?” said the Time Traveller.</p><p>“It’s against reason,” said Filby.</p><p>“What reason?” said the Time Traveller.</p><p>“You can show black is white by argument,” said Filby, “but you will never convince me.”</p><p>“Possibly not,” said the Time Traveller. “But now you begin to see the object of my investigations into the geometry of Four Dimensions. Long ago I had a vague inkling of a machine—”</p><p>“To travel through Time!” exclaimed the Very Young Man.</p><p>“That shall travel indifferently in any direction of Space and Time, as the driver determines.”</p><p>Filby contented himself with laughter.</p><p>“But I have experimental verification,” said the Time Traveller.</p><p>“It would be remarkably convenient for the historian,” the Psychologist suggested. “One might travel back and verify the accepted account of the Battle of Hastings, for instance!”</p><p>“Don’t you think you would attract attention?” said the Medical Man. “Our ancestors had no great tolerance for anachronisms.”</p><p>“One might get one’s Greek from the very lips of Homer and Plato,” the Very Young Man thought.</p><p>“In which case they would certainly plough you for the Little-go. The German scholars have improved Greek so much.”</p><p>“Then there is the future,” said the Very Young Man. “Just think! One might invest all one’s money, leave it to accumulate at interest, and hurry on ahead!”</p><p>“To discover a society,” said I, “erected on a strictly communistic basis.”</p><p>“Of all the wild extravagant theories!” began the Psychologist.</p><p>“Yes, so it seemed to me, and so I never talked of it until—”</p><p>“Experimental verification!” cried I. “You are going to verify <em>that</em>?”</p><p>“The experiment!” cried Filby, who was getting brain-weary.</p><p>“Let’s see your experiment anyhow,” said the Psychologist, “though it’s all humbug, you know.”</p><p>The Time Traveller smiled round at us. Then, still smiling faintly, and with his hands deep in his trousers pockets, he walked slowly out of the room, and we heard his slippers shuffling down the long passage to his laboratory.</p><p>The Psychologist looked at us. “I wonder what he’s got?”</p><p>“Some sleight-of-hand trick or other,” said the Medical Man, and Filby tried to tell us about a conjuror he had seen at Burslem, but before he had finished his preface the Time Traveller came back, and Filby’s anecdote collapsed.</p> Wed, 15 Aug 2018 00:00:00 GMT ttyS3 writingsbookreflection