Compare commits
19 Commits
36397ff348
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 352059915a | |||
| 5070388562 | |||
| 437a8834ce | |||
| c6983b2ba4 | |||
| 54cb3de314 | |||
| b4ed1e436c | |||
| e018df63e0 | |||
| 33b475a3a0 | |||
| 3618328a0b | |||
| d0e6e30c8b | |||
| 70d2505dc5 | |||
| 6145012653 | |||
| f555f04b92 | |||
| ad4e75712f | |||
| bfdfeee8ae | |||
| e2665a4b17 | |||
| a40d08b39c | |||
| dd474b5177 | |||
| 2753c60fca |
4
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
public
|
||||
resources
|
||||
.hugo_build.lock
|
||||
.hugo_build.lock
|
||||
themes/*
|
||||
uv.lock
|
||||
|
||||
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.13
|
||||
130
content/posts/2019/2019-12-22_[Cpp 筆記] 好用的 optional/index.md
Normal file
@@ -0,0 +1,130 @@
|
||||
---
|
||||
slug: "[C++ 筆記] 好用的 std::optional"
|
||||
title: "[C++ 筆記] 好用的 std::optional"
|
||||
description:
|
||||
toc: true
|
||||
authors:
|
||||
- awin
|
||||
tags:
|
||||
- c++
|
||||
categories:
|
||||
- Programming
|
||||
series:
|
||||
- C++ 筆記
|
||||
date: 2019-12-22T00:00:00
|
||||
lastmod: 2019-12-22T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
> since C++17
|
||||
|
||||
[`std::optional`](https://en.cppreference.com/w/cpp/utility/optional) 讓 function 的回傳值多了一個選擇:**有值**或是 `nullopt`。
|
||||
|
||||
<!--more-->
|
||||
|
||||
例如我們有一個 function 要從某個檔案讀值出來(或是去 DB 查一個東西之類的需求),就假設我們要讀一個 int,我們也許會這樣寫:
|
||||
```cpp
|
||||
int readData(std::string filePath) {
|
||||
...
|
||||
int data = readFromFile(...);
|
||||
...
|
||||
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
但如果要讀的檔案不存在呢?這時候要 return 什麼呢?所以這時候我們會改成這樣寫:
|
||||
```cpp
|
||||
bool readData(std::string filePath, int& readData) {
|
||||
FILE* file = fopen(...)
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
readData = readFromFile(...);
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
我們用一個回傳值代表檔案讀取失敗與否,要是檔案存在且開啟成功,那麼 `readData` 這個回傳值就代表我們讀到的值。要是回傳值是 `false`,那 `readData` 就沒有意義。
|
||||
但是這樣會讓傳入跟傳出的參數混在一起,第一時間也不容易直覺的分辨出來,像這種情況 Python 就清楚很多:
|
||||
```python
|
||||
def readData(filePath):
|
||||
data = None
|
||||
try:
|
||||
with open(filePath, "rb") as f:
|
||||
data = f.read(...)
|
||||
return data
|
||||
except FileNotFoundError as e:
|
||||
return None
|
||||
|
||||
value = readData("123.txt")
|
||||
if value:
|
||||
pass # Do something...
|
||||
```
|
||||
可以像 Python 那樣都從回傳值來判斷嗎? `std::optional` 可以達到這個目的:
|
||||
```cpp
|
||||
std::optional<int> readData(std::string filePath) {
|
||||
FILE* file = nullptr;
|
||||
fopen_s(&file, filePath.c_str(), "rb");
|
||||
if (!file) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int readData;
|
||||
fread(&readData, 1, sizeof(readData), file);
|
||||
fclose(file)
|
||||
|
||||
return readData;
|
||||
}
|
||||
|
||||
auto result = readData("123.txt");
|
||||
if (result) {
|
||||
auto value = result.value();
|
||||
// Use value here...
|
||||
}
|
||||
|
||||
// 或是這樣寫也可以
|
||||
if (result == std::nullopt) {
|
||||
// Error handle here
|
||||
} else {
|
||||
auto value = result.value();
|
||||
// Use value here...
|
||||
}
|
||||
```
|
||||
|
||||
雖然用起來沒辦法讓 C++ 像 Python 那麼簡單,但是 `std::optional` 確實讓整段 code 看起來更清楚了。
|
||||
除了 [`std::optional<T>::value()`](https://en.cppreference.com/w/cpp/utility/optional/value) 以外,還有其他的取值方法:
|
||||
```cpp
|
||||
std::optional<std::string> name;
|
||||
|
||||
// Some process...
|
||||
|
||||
if (name)
|
||||
{
|
||||
printf("name = %s\n", (*name).c_str());
|
||||
}
|
||||
```
|
||||
|
||||
如果 `std::optional` 包含的是 struct 或是 class,也可以用 `->` 來直接存取 member(或 member function):
|
||||
```cpp
|
||||
struct User {
|
||||
uint32_t id;
|
||||
std::string name;
|
||||
int32_t age;
|
||||
};
|
||||
|
||||
std::optional<User> user;
|
||||
|
||||
// Some process...
|
||||
|
||||
if (user) {
|
||||
printf("id = %d\n", user->id);
|
||||
printf("name = %s\n", user->name.c_str());
|
||||
printf("age = %d\n", user->age);
|
||||
}
|
||||
```
|
||||
77
content/posts/2021/2021-11-01_Windows 11 重灌/index.md
Normal file
@@ -0,0 +1,77 @@
|
||||
---
|
||||
slug: Windows 11 重灌
|
||||
title: Windows 11 重灌
|
||||
description:
|
||||
toc: true
|
||||
authors: [awin]
|
||||
tags: [windows]
|
||||
categories: [System]
|
||||
series: [Windows]
|
||||
date: 2021-11-01T00:00:00
|
||||
lastmod: 2021-11-01T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
<!--more-->
|
||||
|
||||
## 恢復備份
|
||||
- `%userprofile%/.config`
|
||||
- `%userprofile%/.ssh`
|
||||
- `%userprofile%/.bash_profile`
|
||||
- `%userprofile%/.bashrc`
|
||||
- `%userprofile%/.gitconfig`
|
||||
- `%userprofile%/.vimrc`
|
||||
|
||||
## 安裝 Chocolatey
|
||||
|
||||
先安裝 [Chocolatey](https://chocolatey.org/) ,根據 [https://chocolatey.org/install](https://chocolatey.org/install) ,用 Administrator 權限打開 Terminal ,輸入以下指令安裝:
|
||||
|
||||
```powershell
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
||||
```
|
||||
|
||||
## 安裝需要的軟體
|
||||
|
||||
接著就可以安裝需要的工具了。
|
||||
|
||||
```shell
|
||||
choco install powertoys 7zip vscode hxd sublimetext4 androidstudio intellijidea-community git winmerge freefilesync freedownloadmanager gsudo firacode cascadiacode sourcecodepro delta googlechrome googledrive enpass.install sharex win32diskimager k-litecodecpackmega obsidian anki --yes
|
||||
```
|
||||
|
||||
可以在 [https://community.chocolatey.org/packages](https://community.chocolatey.org/packages) 找到其他工具,再加到清單後面即可。
|
||||
|
||||
上面的指令安裝了下列的軟體,可以依自己需求增刪:
|
||||
|
||||
- [powertoys](https://community.chocolatey.org/packages/powertoys)
|
||||
- [7zip](https://community.chocolatey.org/packages/7zip)
|
||||
- [vscode](https://community.chocolatey.org/packages/vscode)
|
||||
- [hxd](https://community.chocolatey.org/packages/hxd)
|
||||
- [sublimetext4](https://community.chocolatey.org/packages/sublimetext4)
|
||||
- [androidstudio](https://community.chocolatey.org/packages/androidstudio)
|
||||
- [intellijidea-community](https://community.chocolatey.org/packages/intellijidea-community)
|
||||
- [git](https://community.chocolatey.org/packages/git)
|
||||
- [winmerge](https://community.chocolatey.org/packages/winmerge)
|
||||
- [freefilesync](https://community.chocolatey.org/packages/freefilesync)
|
||||
- [freedownloadmanager](https://community.chocolatey.org/packages/freedownloadmanager)
|
||||
- [gsudo](https://community.chocolatey.org/packages/gsudo)
|
||||
- [firacode](https://community.chocolatey.org/packages/firacode)
|
||||
- [cascadiacode](https://community.chocolatey.org/packages/cascadiacode)
|
||||
- [sourcecodepro](https://community.chocolatey.org/packages/sourcecodepro)
|
||||
- [delta](https://community.chocolatey.org/packages/delta)
|
||||
- [googlechrome](https://community.chocolatey.org/packages/googlechrome)
|
||||
- [googledrive](https://community.chocolatey.org/packages/googledrive)
|
||||
- [enpass.install](https://community.chocolatey.org/packages/enpass.install)
|
||||
- [sharex](https://community.chocolatey.org/packages/sharex)
|
||||
- [win32diskimager](https://community.chocolatey.org/packages/win32diskimager)
|
||||
- [k-litecodecpackmega](https://community.chocolatey.org/packages/k-litecodecpackmega)
|
||||
- [obsidian](https://community.chocolatey.org/packages/obsidian)
|
||||
- [anki](https://community.chocolatey.org/packages/anki)
|
||||
|
||||
## 升級軟體
|
||||
|
||||
```shell
|
||||
choco upgrade all -y
|
||||
```
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,47 @@
|
||||
---
|
||||
slug: 用 oh-my-posh 美化 Git bash
|
||||
title: 用 oh-my-posh 美化 Git bash
|
||||
description:
|
||||
toc: true
|
||||
authors:
|
||||
- awin
|
||||
tags:
|
||||
- terminal
|
||||
categories:
|
||||
- Tool setup
|
||||
series:
|
||||
- Windows
|
||||
date: 2022-06-14T00:00:00
|
||||
lastmod: 2022-06-14T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
讓 [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) 中的 Git bash 也可以美美的。
|
||||
|
||||
<!--more-->
|
||||
|
||||
## 步驟
|
||||
以下步驟都是在 [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) 中的 Git bash[^1] 執行。
|
||||
1. 先下載一個你喜歡的theme: [https://ohmyposh.dev/docs/themes](https://ohmyposh.dev/docs/themes)
|
||||
2. 下載並安裝字型:[Caskaydia Cove Nerd Font](https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/CascadiaCode.zip?WT.mc_id=-blog-scottha)
|
||||
3. Install OhMyPosh: `winget install JanDeDobbeleer.OhMyPosh`
|
||||
4. 建立並修改 `~/.profile`,然後加入
|
||||
`eval "$(oh-my-posh --init --shell bash --config ~/montys.omp.json)"`
|
||||
注意最後的 `montys.omp.json` 就是第一步下載的theme,這邊要改成你自己的路徑。
|
||||
5. 修改 Windows Terminal 的 `setting.json`,將字型改為 `CaskaydiaCove NF`
|
||||

|
||||
6. 重開 Windows Terminal
|
||||
|
||||
[^1]: 在 [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) 中設定 Git bash 可以參考:[Windows Terminal's 設定 Git Bash 和 SSH @ 傑克! 真是太神奇了! :: 痞客邦 ::](https://magicjackting.pixnet.net/blog/post/225162505-windows-terminal's-%E8%A8%AD%E5%AE%9A-git-bash-%E5%92%8C-ssh)
|
||||
|
||||
## 成果
|
||||

|
||||
|
||||
## 參考
|
||||
- [Oh My Posh](https://ohmyposh.dev/)
|
||||
- [How to make the ultimate Terminal Prompt on Windows 11 - This video is LONG and WORDY and DETAILED - YouTube](https://www.youtube.com/watch?v=VT2L1SXFq9U)
|
||||
- [My Ultimate PowerShell prompt with Oh My Posh and the Windows Terminal - Scott Hanselman's Blog](https://www.hanselman.com/blog/my-ultimate-powershell-prompt-with-oh-my-posh-and-the-windows-terminal)
|
||||
- [Windows-Terminal配置OhMyPosh来美化GitBash_偕臧x的博客-CSDN博客](https://blog.csdn.net/qq_33154343/article/details/120661945)
|
||||
BIN
content/posts/2023/2023-02-15_福岡 Nu Gundam/featured.jpg
Normal file
|
After Width: | Height: | Size: 484 KiB |
|
After Width: | Height: | Size: 638 KiB |
|
After Width: | Height: | Size: 634 KiB |
|
After Width: | Height: | Size: 592 KiB |
25
content/posts/2023/2023-02-15_福岡 Nu Gundam/index.md
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
slug: 福岡 Nu Gundam
|
||||
title: 福岡 Nu Gundam
|
||||
description:
|
||||
toc: true
|
||||
authors:
|
||||
- awin
|
||||
tags:
|
||||
- Gunpla
|
||||
categories:
|
||||
- Hobby
|
||||
series:
|
||||
- Scale Model
|
||||
date: 2023-02-15T00:00:00
|
||||
lastmod: 2023-02-15T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
繼台場 RX-78 與 Unicorn 之後,很開心終於收集到了 LaLaport 的 Nu Gundam,下一個目標,當然就是橫濱的 RX-78 F00 啦!
|
||||

|
||||

|
||||

|
||||
29
content/posts/2023/2023-03-03_解決 Qt 線上安裝很慢的問題/index.md
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
slug: 解決 Qt 線上安裝很慢的問題
|
||||
title: 解決 Qt 線上安裝很慢的問題
|
||||
description:
|
||||
toc: true
|
||||
authors: [awin]
|
||||
tags: [qt]
|
||||
categories: [Programming]
|
||||
series: [Software note]
|
||||
date: 2023-03-03T00:00:00
|
||||
lastmod: 2023-03-03T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
`qt-unified-windows-x86-4.0.1-1-online.exe` 預設的 server 真的很慢,甚至會發生校驗錯誤的情況。
|
||||
|
||||
<!--more-->
|
||||
|
||||
可以在[Qt Downloads](https://download.qt.io/static/mirrorlist/)選 mirror server,然後在安裝的時候指定使用它。
|
||||
|
||||
例如我選的是 Yamagata University 的 mirror server,如下:
|
||||
```cmd
|
||||
qt-unified-windows-x64-4.7.0-online.exe --mirror https://ftp.yz.yamagata-u.ac.jp/pub/qtproject/
|
||||
```
|
||||
|
||||
下載速度從 1~2 MB/s 進步到 25MB/s 左右。
|
||||
BIN
content/posts/2023/2023-04-08_Fujifilm X-T5 入手感想/featured.jpg
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
62
content/posts/2023/2023-04-08_Fujifilm X-T5 入手感想/index.md
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
slug: Fujifilm X-T5 入手感想
|
||||
title: Fujifilm X-T5 入手感想
|
||||
description:
|
||||
toc: true
|
||||
authors:
|
||||
- awin
|
||||
tags:
|
||||
- photography
|
||||
- fujifilm
|
||||
- x-t5
|
||||
categories:
|
||||
- Hobby
|
||||
series: []
|
||||
date: 2023-04-08T00:00:00
|
||||
lastmod: 2023-04-08T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
買了 X-T5 也一陣子了,機器功能什麼的是很OK的,尤其跟前一台比起來,性能、感光度什麼的都是大幅度的進步,滿滿的升級感。
|
||||
|
||||
只是使用上還是不習慣,這一篇來講一下不習慣的點,還有解決方法。
|
||||
|
||||
<!--more-->
|
||||
|
||||
雖然 X-T5 的轉盤很漂亮很有型,但是要一直轉來轉去也是有點煩人,像是你將設定快門之後(快門先決),要改成A模式(光圈先決),先得把快門轉回A,然後再把光圈轉到你要的位置,如果這時候要回到P模式,對,快門轉盤跟光圈環都要調回A才行。也不是不好,就是有點煩人。
|
||||
|
||||
第二個不習慣的點是我還是習慣用觀景窗來取景,要調整轉盤的話,變成要將相機放下來,轉動轉盤,再把相機拿起來取景,尤其是ISO轉盤,它在左手邊,要由本來扶著鏡頭的左手來調整,一整個就很不順手。我還是希望可以在取景的時候,用右手就可以改變設定,不用把相機拿上拿下的。
|
||||
|
||||
另外一個問題是X-T5的握把實在太淺了,有夠難握,這時候就很懷念前一台那厚實的握把,可以牢牢握住的那種踏實感。
|
||||
|
||||
這邊紀錄一下這幾個問題的解決方法。
|
||||
|
||||
## 握把
|
||||
關於握把,是買[Smallrig 3870](https://www.smallrig.com/SmallRig-Retro-Cage-for-FUJIFILM-X-T5-3870.html),這個兔籠可以加深握把,而且也把快門鈕的位置往前移,但是它往前移的機構並沒有做的很好,必須按連桿中間部份才可以有效的對焦。看下面的影片,一開始按連桿的前面(也就是它原本預計要把快門前移的位置),你會發現按下去之後,連桿沒辦法順利的拉動原本的快門鈕,必須按中間一點的位置才行。
|
||||
|
||||
{{< video src="images/IMG_6330.mp4" type="video/mp4" preload="auto" >}}
|
||||
|
||||
雖然不完美,但是握把真的舒服太多了,所以這點瑕不掩瑜,是一個可以適應的小問題。
|
||||
|
||||
## 滾輪控制
|
||||
第二個問題是希望可以把光圈、快門、ISO的調整都改為用右手的前後滾輪來控制,這樣就可以在取景的時候直接調整了。要達到這目標有幾個地方要調整:
|
||||
1. 光圈環調成 "A"
|
||||
2. ISO 轉盤調成 "C"
|
||||
3. EV 轉盤調成 "C"
|
||||
4. 設定選單,進入「設定」頁面的「按鈕/轉盤設定」,將前轉盤的3個功能改為「F」、「EV」、「ISO」
|
||||
5. 同樣的選單位置,將後轉盤改為「S.S」
|
||||
|
||||
| | | |
|
||||
|:-------------------------:|:-------------------------:|:-------------------------:|
|
||||
|  |  |  |
|
||||
|
||||
這樣設定之後,後轉盤可以用來控制快門,前轉盤可以控制光圈、EV、ISO這3樣。
|
||||
現在相機會變為「P模式」,將快門轉盤轉到 "T" 之後就會變成「S模式」,這時候可以用後轉盤來調整快門。
|
||||
將快門轉盤調回 A,將前轉盤「向左轉」,這時候會出現藍色的光圈數值,這時候就是「A模式」了。
|
||||
按下前轉盤可以在光圈、EV、ISO之中切換。如果快門轉盤沒有調回 A,那麼就是「M模式」,總之一切都可以在這2個轉盤中搞定了。
|
||||
唯一還是需要用到轉盤的就是快門轉盤了,不過從A調到T只要2格,這不容易弄錯,很快就可以熟悉了。
|
||||
|
||||
後來我發現X-H2就是我想要的這種操作模式,如果這樣的設定還是用不習慣,看來只能......🤣。
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
slug: Dokcer Compose 遇到 Python 3.6 不再支援問題
|
||||
title: Dokcer Compose 遇到 Python 3.6 不再支援問題
|
||||
description:
|
||||
toc: true
|
||||
authors:
|
||||
- awin
|
||||
tags: []
|
||||
categories: []
|
||||
series: []
|
||||
date: 2023-05-09T00:00:00
|
||||
lastmod: 2023-05-09T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
解決 `docker-compose` 警告 Python 3.6 不再支援問題。
|
||||
|
||||
<!--more-->
|
||||
|
||||
可能已經發生一時間了,但是最近才注意到 XD。
|
||||
|
||||
在使用 `docker-compose down` 或是 `docker-compose up`,都會出現下面這個訊息:
|
||||
|
||||
```bash
|
||||
/snap/docker/2746/lib/python3.6/site-packages/paramiko/transport.py:32: CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography. The next release of cryptography (40.0) will be the last to support Python 3.6.
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
```
|
||||
|
||||
雖然已經確定使用 Python 3.10,查看 docker-compose 版本也確實發現它還是使用 Python 3.6:
|
||||
|
||||
```bash
|
||||
xxxx@xxxx:~/oooo/ooxx$ sudo docker-compose version
|
||||
/snap/docker/2746/lib/python3.6/site-packages/paramiko/transport.py:32: CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography. The next release of cryptography (40.0) will be the last to support Python 3.6.
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
docker-compose version 1.29.2, build unknown
|
||||
docker-py version: 5.0.3
|
||||
CPython version: 3.6.9
|
||||
```
|
||||
|
||||
這是因為 `docker-compose` 這個命令已經過時了,請改用 `docker compose` 就可以了。<br>
|
||||
要是習慣改不過來,不妨就加個alias吧:
|
||||
|
||||
```bash
|
||||
alias docker-compose='docker compose'
|
||||
```
|
||||
60
content/posts/2024/2024-01-08_線上備份樹莓派/index.md
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
slug: 線上備份樹莓派
|
||||
title: 線上備份樹莓派
|
||||
description:
|
||||
toc: true
|
||||
authors: [awin]
|
||||
tags: [raspberrypi]
|
||||
categories: [system]
|
||||
series: [Raspberry Pi]
|
||||
date: 2024-01-08T00:00:00
|
||||
lastmod: 2024-01-08T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
`image-backup` 是 `image-utils` 裡面的一個工具,可以直接把樹莓派系統直接備份到另一個檔案,不用拔卡或是關機,非常方便。
|
||||
<!--more-->
|
||||
`image-utils` 的Github repo在:[seamusdemora/RonR-RPi-image-utils: tools to create a backup of a running Raspbian system to an SD card image file](https://github.com/seamusdemora/RonR-RPi-image-utils)
|
||||
|
||||
## 安裝 `image-utils`
|
||||
```shell
|
||||
cd && mkdir ~/image-utilities && cd ~/image-utilities
|
||||
wget -O image.zip "https://forums.raspberrypi.com/download/file.php?id=63044&sid=58c9d2d90272e5ae96c12a58a30731d9"
|
||||
unzip ./image.zip
|
||||
chmod a+x image-*
|
||||
```
|
||||
|
||||
## 備份
|
||||
在 `~/image-utilities` 目錄下執行 `image-backup` 會以對話的方式來備份,像是這樣:
|
||||
```shell
|
||||
sudo ./image-backup
|
||||
|
||||
Image file to create? /media/backup/pi4_sd_backup.img ## 輸入檔案路徑,例子是/media/backup/pi4_sd_backup.img
|
||||
|
||||
Initial image file ROOT filesystem size (MB) [11631]? ## 按 Enter 跳過,使用 default 值
|
||||
|
||||
Added space for incremental updates after shrinking (MB) [0]? ## 按 Enter 跳過,使用 default 值
|
||||
|
||||
Create /media/backup/pi4_sd_backup.img (y/n)? y ## 按 y
|
||||
```
|
||||
|
||||
然後就會開始備份系統,過程會花上一些時間,取決於你的系統大小與檔案寫的速度。
|
||||
|
||||
## 自動備份
|
||||
但是這樣每次都要手動操作很麻煩,像下面這樣一個命令解決比較方便:
|
||||
```shell
|
||||
sudo ./image-backup -i /media/backup/pi4.img
|
||||
```
|
||||
|
||||
這樣就可以透過`crontab`自動執行了。
|
||||
|
||||
## 增量備份
|
||||
如果已經備份過系統,下次備份的時候有指定上一次的備份檔,就會做增量備份,如下:
|
||||
```shell
|
||||
sudo ./image-backup /media/upload/pi4.img
|
||||
```
|
||||
|
||||
注意沒有 `-i` 這個選項。
|
||||
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 371 B |
@@ -0,0 +1,361 @@
|
||||
---
|
||||
slug: LXC 安裝 Windows 11,並分享 i915 內顯
|
||||
title: LXC 安裝 Windows 11,並分享 i915 內顯
|
||||
description:
|
||||
toc: true
|
||||
authors: [awin]
|
||||
tags: [linux, lxc, windows]
|
||||
categories: [system]
|
||||
series: [Windows, Linux]
|
||||
date: 2024-04-01T00:00:00
|
||||
lastmod: 2024-04-01T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
這裡分享我在 Ubuntu Server 22.04 用 LXC 安裝 Windows 11,以及分享內顯 i915給虛擬機的的紀錄。
|
||||
要讓虛擬機可以使用 GPU,最常見的是 GPU passthrough,但是 GPU passthrough 只能給一個虛擬機使用,要讓多個虛擬機同時使用的話,必須打開 i915 的 SR-IOV ,可以多 7 個 VGA 來分享給虛擬機。
|
||||
|
||||
<!--more-->
|
||||
|
||||
## 準備
|
||||
|
||||
### 安裝 incus
|
||||
|
||||
根據 https://linuxcontainers.org/incus/docs/main/installing/#installing 的說明,Ubuntu 22.04 還沒辦法使用 apt 來安裝,因此依照 https://github.com/zabbly/incus 的說明來安裝:
|
||||
|
||||
```shell
|
||||
curl -fsSL https://pkgs.zabbly.com/key.asc | gpg --show-keys --fingerprint
|
||||
mkdir -p /etc/apt/keyrings/
|
||||
sudo curl -fsSL https://pkgs.zabbly.com/key.asc -o /etc/apt/keyrings/zabbly.asc
|
||||
|
||||
sudo sh -c 'cat <<EOF > /etc/apt/sources.list.d/zabbly-incus-stable.sources
|
||||
Enabled: yes
|
||||
Types: deb
|
||||
URIs: https://pkgs.zabbly.com/incus/stable
|
||||
Suites: $(. /etc/os-release && echo ${VERSION_CODENAME})
|
||||
Components: main
|
||||
Architectures: $(dpkg --print-architecture)
|
||||
Signed-By: /etc/apt/keyrings/zabbly.asc
|
||||
EOF'
|
||||
|
||||
sudo apt update
|
||||
sudo apt install incus
|
||||
```
|
||||
|
||||
### 設定 incus
|
||||
|
||||
使用 `sudo incus admin init` 來設定,會問一堆問題,如下:
|
||||
|
||||
```
|
||||
Would you like to use clustering? (yes/no) [default=no]:
|
||||
Do you want to configure a new storage pool? (yes/no) [default=yes]: no
|
||||
Would you like to create a new local network bridge? (yes/no) [default=yes]: no
|
||||
Would you like to use an existing bridge or host interface? (yes/no) [default=no]: yes
|
||||
Name of the existing bridge or host interface: enp3s0
|
||||
Would you like the server to be available over the network? (yes/no) [default=no]: yes
|
||||
Address to bind to (not including port) [default=all]:
|
||||
Port to bind to [default=8443]:
|
||||
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]:
|
||||
Would you like a YAML "init" preseed to be printed? (yes/no) [default=no]:
|
||||
```
|
||||
|
||||
大部分都預設就可以。
|
||||
|
||||
### 建立 pool
|
||||
|
||||
```shell
|
||||
sudo incus storage create vmpool dir source=/lvm1/lxd_storage
|
||||
```
|
||||
|
||||
### 建立 profile
|
||||
|
||||
```shell
|
||||
sudo incus profile copy default windows
|
||||
```
|
||||
|
||||
編輯profile,內容如下:
|
||||
|
||||
```
|
||||
config:
|
||||
limits.cpu: "16"
|
||||
limits.memory: 16GiB
|
||||
raw.qemu: -device intel-hda -device hda-duplex -audio spice
|
||||
description: 'Windows: 16CPU, 16GB RAM, 1024GB DISK'
|
||||
devices:
|
||||
eth0:
|
||||
name: eth0
|
||||
nictype: macvlan
|
||||
parent: br0
|
||||
type: nic
|
||||
root:
|
||||
path: /
|
||||
pool: vmpool
|
||||
type: disk
|
||||
vtpm:
|
||||
path: /dev/tpm0
|
||||
type: tpm
|
||||
name: windows
|
||||
used_by: []
|
||||
```
|
||||
|
||||
### 安裝需要的套件
|
||||
|
||||
```shell
|
||||
sudo apt-get install genisoimage libguestfs-tools wimtools --yes
|
||||
sudo snap install distrobuilder --classic
|
||||
```
|
||||
|
||||
### 轉換 ISO
|
||||
|
||||
我們需要把Windows ISO轉換為lxc可用的ISO,先準備好原本的Windows ISO,這裡的檔名是 `Win11_23H2_Chinese_Traditional_x64v2.iso`,記得換成你自己的檔名。
|
||||
命令如下:
|
||||
|
||||
```shell
|
||||
sudo distrobuilder repack-windows Win11_23H2_Chinese_Traditional_x64v2.iso Win11_23H2_Chinese_Traditional_x64v2.lxd.iso
|
||||
```
|
||||
|
||||
我們把 `Win11_23H2_Chinese_Traditional_x64v2.iso` 轉為 `Win11_23H2_Chinese_Traditional_x64v2.lxd.iso`。
|
||||
|
||||
等一下 `Win11_23H2_Chinese_Traditional_x64v2.lxd.iso` 就是要餵給虛擬機安裝的檔案。
|
||||
|
||||
### 讓操作端跟 server 端可以互連
|
||||
|
||||
因為 Ubuntu server 沒有 GUI,都是透過命令操作,所以當虛擬機開機之後沒有辦法顯示畫面。所以我們需要從另一台 Windows 來把虛擬機開機,並在這台 Windows 上顯示並操作安裝畫面,這樣才可以安裝 Windows 虛擬機。
|
||||
|
||||
Ubuntu server 我們就稱為 server 端。
|
||||
Windows 這邊我們就稱為操作端。
|
||||
|
||||
#### server 端
|
||||
|
||||
這邊我們要讓 lxc 新增一個操作端,如下:
|
||||
|
||||
```shell
|
||||
sudo incus config trust add awn-pc1
|
||||
```
|
||||
|
||||
然後會跳出一堆字串,類似這樣:
|
||||
|
||||
```
|
||||
ucRZ8JO48d4J32MRZ1tuuvNh3Wg86Pb7LZ4QKk090BM3jA2SIRh9aDB1mQ4dZ0H76PJll1bb0YkG2ZK8l5YYPWX5Cw4UhVs2li722P5s7A45MW4B5WBXBQXFPT170L50MsMMjB8ZiVhO6Ug2JWXGwdxp897u8cELqE6AAbA901uUCBwo80qr5czfR2Pk3QS7JCRb9LFa6uKKQsQKSDHm76814UOD3Knf50E9cq3GB6C28A0B54NKBw9T5004ZQ75QqCZqBD0F32mjfAILGCI57R09RN81LHMJ0NLVAXAKQc2LTh0aHYjsO6J41ERLAQF8bk7T07cG4611YT6F57Y6lr93ZSc5L0W7F5R5RG7Xr6e0gJ6dXh5iI18uwpUrZ6MAhN6GSUSGYTqe218He5gLa3G3UMNAJY1PlLSShcV91UF3Z18QloVR8DP9O6wYa7R9LG2Cv04MDSIK8Hs94ZPQ4hsbS1BT2J5QqZ41su06R9a8WTjP9rX8hNsQz5x5744AJl2656SdUqbos4JKX9B2IbGheqK94D7Ya0SZYiODX7Y5rIWdH1P6M6e5J75nN6En0Y9UmgRCGE2WIeG6jXFhpb7
|
||||
```
|
||||
|
||||
這個記下來,等一下要在操作端輸入。
|
||||
|
||||
#### 操作端
|
||||
|
||||
命令:
|
||||
|
||||
```
|
||||
incus remote add awin-pc2 192.168.1.24
|
||||
```
|
||||
|
||||
然後輸入剛剛那一串字串。
|
||||
|
||||
接著命令:
|
||||
|
||||
```
|
||||
incus switch awin-pc2
|
||||
```
|
||||
|
||||
之後就可以在操作端啟動 server 端的虛擬機了。
|
||||
|
||||
## 建立虛擬機
|
||||
|
||||
server 端命令:
|
||||
|
||||
```shell
|
||||
sudo incus init --empty --vm --profile=windows MY-VM-WIN11
|
||||
sudo incus config device add MY-VM-WIN11 install disk source=/home/awin/lxd/Win11_23H2_Chinese_Traditional_x64v2.lxd.iso boot.priority=10
|
||||
```
|
||||
|
||||
操作端命令:
|
||||
|
||||
```shell
|
||||
incus start MY-VM-WIN11 --console=vga
|
||||
```
|
||||
|
||||
操作端會跳出一個新視窗,然後就是 Windows 的安裝流程,記得在 "Press any key to boot from CD" 文字出現的時候趕快按一個鍵進入安裝流程。
|
||||
來不及的話,左上角按鈕可以發送 `ctrl+alt+del` 來重新開機。
|
||||
|
||||
這邊要注意的是,一旦發生重開機的狀況,剛剛那個視窗會關掉,然後跳一堆錯誤訊息,像是:
|
||||
|
||||
```
|
||||
(remote-viewer.exe:23816): GSpice-CRITICAL **: 22:48:14.989: _usbdk_hider_update: assertion 'priv->usbdk_api != NULL' failed
|
||||
|
||||
(remote-viewer.exe:23816): GLib-GIO-WARNING **: 22:48:15.475: Unexpectedly, UWP app `Microsoft.OutlookForWindows_1.2024.214.400_x64__8wekyb3d8bbwe' (AUMId `Microsoft.OutlookForWindows_8wekyb3d8bbwe!Microsoft.OutlookforWindows') supports 4 extensions but has no verbs
|
||||
|
||||
(remote-viewer.exe:23816): GLib-GIO-WARNING **: 22:48:15.598: Unexpectedly, UWP app `Microsoft.ScreenSketch_11.2401.37.0_x64__8wekyb3d8bbwe' (AUMId `Microsoft.ScreenSketch_8wekyb3d8bbwe!App') supports 29 extensions but has no verbs
|
||||
|
||||
(remote-viewer.exe:23816): GLib-GIO-WARNING **: 22:48:15.600: Unexpectedly, UWP app `Clipchamp.Clipchamp_3.0.10220.0_neutral__yxz26nhyzhsrt' (AUMId `Clipchamp.Clipchamp_yxz26nhyzhsrt!App') supports 41 extensions but has no verbs
|
||||
|
||||
(remote-viewer.exe:23816): GSpice-CRITICAL **: 22:48:15.677: _usbdk_hider_update: assertion 'priv->usbdk_api != NULL' failed
|
||||
|
||||
(remote-viewer.exe:23816): GSpice-WARNING **: 22:48:15.677: Warning no automount-inhibiting implementation available
|
||||
Error: tls: failed to send closeNotify alert (but connection was closed anyway): write tcp 192.168.1.24:8443->192.168.1.154:50714: write: broken pipe
|
||||
```
|
||||
|
||||
這時用 `incus console MY-VM-WIN11 --type=vga` 就可以再次連上已開機的虛擬機,不要用 `incus start MY-VM-WIN11 --console=vga`。
|
||||
只要虛擬機沒有關機,就是用 `incus console MY-VM-WIN11 --type=vga` 來連上畫面。
|
||||
關機的情況下才是用 `incus start MY-VM-WIN11 --console=vga` 來開機並顯示畫面。
|
||||
|
||||
再來 Windows 11 沒有網路會無法安裝,所以要跳過網路檢查,在最早的安裝畫面按 `shift+F10` 打開 command line,然後輸入:
|
||||
|
||||
```
|
||||
oobe/bypassnro
|
||||
```
|
||||
|
||||
安裝之後,把虛擬機連上 macvlan。
|
||||
|
||||
```shell
|
||||
sudo incus config device override MY-VM-WIN11 eth0 nictype=macvlan
|
||||
```
|
||||
|
||||
這樣虛擬機就有網路了。
|
||||
|
||||
### 虛擬機裝好之後
|
||||
|
||||
#### 虛擬機操作
|
||||
|
||||
1. 把遠端桌面連線打開
|
||||
2. 下載 driver: [virtio-win-guest-tools.exe](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.248-1/virtio-win-guest-tools.exe) ,然後安裝。
|
||||
|
||||
## 分享內顯給虛擬機
|
||||
|
||||
### 準備
|
||||
|
||||
安裝需要的套件
|
||||
|
||||
```shell
|
||||
apt install build-* dkms
|
||||
```
|
||||
|
||||
確認你的 kernel 是 6.1 ~ 6.5:
|
||||
|
||||
```shell
|
||||
uname -r
|
||||
# 6.5.0-26-generic
|
||||
```
|
||||
|
||||
### 安裝 i915 Driver
|
||||
|
||||
下載 i915 Driver:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/strongtz/i915-sriov-dkms
|
||||
```
|
||||
|
||||
進到剛剛 clone 的目錄,修改 `dkms.conf`,把 `PACKAGE_NAME` 改為 `"i915-sriov-dkms"`,把 `PACKAGE_VERSION` 改為 `"6.5"`,看你的 kernel 版號多少就改多少。我的版本是 6.5 ,所以這裡填 6.5。
|
||||
|
||||
```shell
|
||||
cd i915-sriov-dkms
|
||||
nano dkms.conf
|
||||
|
||||
# 前 2 行改成這樣
|
||||
# dkms.conf
|
||||
PACKAGE_NAME="i915-sriov-dkms"
|
||||
PACKAGE_VERSION="6.5"
|
||||
```
|
||||
|
||||
安裝 driver:
|
||||
|
||||
```shell
|
||||
# 記得要在 i915-sriov-dkms 這目錄裡面
|
||||
dkms add .
|
||||
dkms install -m i915-sriov-dkms -v 6.5
|
||||
dkms remove -m i915-sriov-dkms -v 6.5
|
||||
dkms install -m i915-sriov-dkms -v 6.5
|
||||
```
|
||||
|
||||
如果有出現類似以下的錯誤:
|
||||
|
||||
```
|
||||
update-initramfs: Generating /boot/initrd.img-6.5.0-26-generic
|
||||
W: Possible missing firmware /lib/firmware/i915/mtl_gsc_102.0.0.1511.bin for module i915
|
||||
W: Possible missing firmware /lib/firmware/i915/mtl_huc_8.4.3_gsc.bin for module i915
|
||||
W: Possible missing firmware /lib/firmware/i915/mtl_guc_70.6.4.bin for module i915
|
||||
```
|
||||
|
||||
去 [https://cgit.freedesktop.org/drm/drm-firmware/refs/](https://cgit.freedesktop.org/drm/drm-firmware/refs/) 把檔案找出來,放到 `/lib/firmware/i915/` 然後再重新安裝。
|
||||
|
||||
檢查是否有安裝成功:
|
||||
|
||||
```shell
|
||||
modinfo i915 | grep vf
|
||||
|
||||
# 應該要出現如下訊息
|
||||
# parm: max_vfs:Limit number of virtual functions to allocate. (0 = no VFs [default]; N = allow up to N VFs) (uint)
|
||||
```
|
||||
|
||||
如果沒有就重新安裝試試。
|
||||
|
||||
修改 grub:
|
||||
|
||||
```shell
|
||||
nano /etc/default/grub
|
||||
|
||||
# "GRUB_CMDLINE_LINUX_DEFAULT" 這一行加入:"quiet intel_iommu=on i915.enable_guc=3 i915.max_vfs=7",如下:
|
||||
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on i915.enable_guc=3 i915.max_vfs=7"
|
||||
```
|
||||
|
||||
更新 grub 和 initramfs:
|
||||
|
||||
```shell
|
||||
update-initramfs -u -k all
|
||||
update-grub
|
||||
```
|
||||
|
||||
開機自動自動設定 vGPU 的數量:
|
||||
|
||||
```shell
|
||||
sudo nano /etc/rc.local
|
||||
|
||||
# 加入
|
||||
echo 7 > /sys/devices/pci0000:00/0000:00:02.0/sriov_numvfs
|
||||
```
|
||||
|
||||
然後 `sudo chmod +x /etc/rc.local`
|
||||
|
||||
重開機,開機之後檢查 VGA 數量是不是有 8 個(1 個是原本的,另外 7 個是可以分享給虛擬機的 )。
|
||||
|
||||
```shell
|
||||
lspci | grep 00:02
|
||||
|
||||
# 應該找到 8 個
|
||||
00:02.0 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.1 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.2 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.3 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.4 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.5 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.6 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.7 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
```
|
||||
|
||||
### 設定 vGPU 給虛擬機
|
||||
|
||||
可以分享的 VGA 有 `00:02.1` ~ `00:02.7` ,然後在虛擬機裡面新增一個 device:
|
||||
|
||||
```shell
|
||||
sudo incus config device add MY-VM-WIN11 gpu pci address=0000:00:02.1
|
||||
```
|
||||
|
||||
然後在操作端把虛擬機開機:
|
||||
|
||||
```
|
||||
incus start MY-VM-WIN11 --console=vga
|
||||
```
|
||||
|
||||
這時後會變成黑畫面,像這樣:
|
||||

|
||||
|
||||
大概等個 1~3 分鐘就會跳出開機畫面了。
|
||||
|
||||
開機好之後,裝置管理員會出現一張顯卡,去 Windows Update 更新,就會出現 Intel UHD 770 顯示卡了。
|
||||
|
||||
### 分數
|
||||
Furmark 2 分數
|
||||

|
||||
|
||||
不優,但總比沒有強。
|
||||
BIN
content/posts/2025/Win32 Disk Imager 無法執行/featured.jpg
Normal file
|
After Width: | Height: | Size: 292 KiB |
26
content/posts/2025/Win32 Disk Imager 無法執行/index.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
slug: Win32 Disk Imager 無法執行
|
||||
title: Win32 Disk Imager 無法執行
|
||||
description:
|
||||
toc: true
|
||||
authors: [awin]
|
||||
tags: [windows, win32diskimager]
|
||||
categories: [system]
|
||||
series: [Windows]
|
||||
date: 2025-04-16T00:00:00
|
||||
lastmod: 2025-04-16T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
紀錄一下 [Win32 Disk Imager](https://sourceforge.net/projects/win32diskimager/) 在 Windows 11 上無法使用與解決方法。
|
||||
|
||||
<!--more-->
|
||||
|
||||
先說結論:**把 Google Drive 關掉就可以了**。
|
||||
|
||||
如果你有其他虛擬磁碟,像是 ISO 虛擬光碟也可能有影響。
|
||||
|
||||
之前應該應該也有遇到同樣的問題,但是可能久久用一次就給忘了,這一次寫下來紀錄一下。
|
||||
BIN
content/posts/2025/uv 簡單介紹/featured.jpg
Normal file
|
After Width: | Height: | Size: 45 KiB |
311
content/posts/2025/uv 簡單介紹/index.md
Normal file
@@ -0,0 +1,311 @@
|
||||
---
|
||||
slug: uv 簡單介紹
|
||||
title: uv 簡單介紹
|
||||
description:
|
||||
toc: true
|
||||
authors: [awin]
|
||||
tags: [python, uv]
|
||||
categories: [Programming]
|
||||
series: ["Software note"]
|
||||
date: 2025-03-09T00:00:00
|
||||
lastmod: 2025-03-09T00:00:00
|
||||
featuredVideo:
|
||||
featuredImage:
|
||||
draft: false
|
||||
enableComment: true
|
||||
---
|
||||
|
||||
[uv](https://github.com/astral-sh/uv) 是一個很方便的 Python 管理工具。這裡是一個簡單的介紹,詳細說明請看[uv 的說明文件](https://docs.astral.sh/uv/)。
|
||||
|
||||
<!--more-->
|
||||
|
||||
## Install uv
|
||||
依官方的步驟來安裝 [Installation | uv](https://docs.astral.sh/uv/getting-started/installation/#standalone-installer)。
|
||||
|
||||
|
||||
## 管理 Python 版本
|
||||
### 列出可安裝的 Python 版本
|
||||
用 [`uv python list`](https://docs.astral.sh/uv/reference/cli/#uv-python-list) 可以列出可安裝的 Python 版本。
|
||||
如果你已經有安裝某個版本了,`<download available>` 會變成你的安裝路徑。
|
||||
```bash
|
||||
❯ uv python list
|
||||
cpython-3.14.0a5+freethreaded-windows-x86_64-none <download available>
|
||||
cpython-3.14.0a5-windows-x86_64-none <download available>
|
||||
cpython-3.13.2+freethreaded-windows-x86_64-none <download available>
|
||||
cpython-3.13.2-windows-x86_64-none <download available>
|
||||
cpython-3.12.9-windows-x86_64-none <download available>
|
||||
cpython-3.11.11-windows-x86_64-none <download available>
|
||||
cpython-3.10.16-windows-x86_64-none <download available>
|
||||
cpython-3.9.21-windows-x86_64-none <download available>
|
||||
cpython-3.8.20-windows-x86_64-none <download available>
|
||||
cpython-3.7.9-windows-x86_64-none <download available>
|
||||
pypy-3.11.11-windows-x86_64-none <download available>
|
||||
pypy-3.10.16-windows-x86_64-none <download available>
|
||||
pypy-3.9.19-windows-x86_64-none <download available>
|
||||
pypy-3.8.16-windows-x86_64-none <download available>
|
||||
pypy-3.7.13-windows-x86_64-none <download available>
|
||||
```
|
||||
|
||||
|
||||
### 安裝 Python
|
||||
使用 [`uv python install <python_version>`](https://docs.astral.sh/uv/reference/cli/#uv-python-install) 可以安裝指定的版本,例:
|
||||
```shell
|
||||
uv python install 3.9 3.11 3.13
|
||||
```
|
||||
這樣就會安裝 `3.9`、`3.11`、`3.13` 這三個版本。
|
||||
|
||||
如果 `uv python install` 沒有指定版本的話,就會安裝目前能下載的最新版本。
|
||||
|
||||
|
||||
### 移除 Python
|
||||
用 `uv python uninstall <python_version>` 來移除一個或多個 Python 版本,`<python_version>` 一定要給。
|
||||
|
||||
|
||||
### Python 安裝路徑
|
||||
[`uv python dir`](https://docs.astral.sh/uv/reference/cli/#uv-python-dir) 會列出目前已安裝的 Python 路徑。
|
||||
|
||||
|
||||
## 專案管理
|
||||
### 單一檔案的專案
|
||||
先從簡單的開始,如果你寫了有一個檔案,可以用 uv 來管理它,當你把它 copy 給人的時候,只要用 [`uv run <your_file.py>`](https://docs.astral.sh/uv/reference/cli/#uv-run) ,uv 就可以幫你完成相依套件的安裝,讓檔案可以順利執行。
|
||||
|
||||
先從建立檔案開始,例:
|
||||
```shell
|
||||
uv init --python 3.11 --script hello.py
|
||||
```
|
||||
|
||||
這邊我們讓 uv 幫我們建立 `hello.py` 這個檔案,使用的環境是 Python 3.11。如果你沒有安裝 Python 3.11 ,那麼 uv 會自動幫你安裝,很方便吧。
|
||||
|
||||
`hello.py` 的內容:
|
||||
```python
|
||||
# /// script
|
||||
# requires-python = ">=3.11"
|
||||
# dependencies = []
|
||||
# ///
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Hello from hello.py!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
前4行就是給 uv 看的 metadata,uv 靠它來維護執行環境與套件。
|
||||
|
||||
|
||||
#### 安裝套件
|
||||
使用 [`uv add`](https://docs.astral.sh/uv/reference/cli/#uv-add) 來安裝套件,假設我們需要使用 `rich` 這個套件:
|
||||
```
|
||||
> uv add rich --script hello.py
|
||||
Updated `hello.py`
|
||||
```
|
||||
|
||||
`hello.py` 的內容會變成:
|
||||
```python
|
||||
# /// script
|
||||
# requires-python = ">=3.11"
|
||||
# dependencies = [
|
||||
# "rich",
|
||||
# ]
|
||||
# ///
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Hello from hello.py!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
可以看到 dependencies 增加了 rich 套件。之後你將 `hello.py` 傳給別人,那人只需要用 `uv run hello.py`,uv 就會自動安裝需要的 Python 版本與相依套件。
|
||||
|
||||
|
||||
#### 移除套件
|
||||
用 [`uv remove`](https://docs.astral.sh/uv/reference/cli/#uv-remove) 可以移除套件,例如 `uv remove rich --script hello.py`。uv 就會將 rich 從 metadata 移除。
|
||||
|
||||
|
||||
### 資料夾的專案
|
||||
實務上單一檔案還是不方便,uv 管理資料夾是用 [`uv init`](https://docs.astral.sh/uv/reference/cli/#uv-init),例:
|
||||
```
|
||||
uv init hello_uv --python 3.13
|
||||
```
|
||||
|
||||
uv 會建立 hello_uv 資料夾,Python 版本是 3.13。
|
||||
資料夾的內容會有:
|
||||
```
|
||||
.git
|
||||
.gitignore
|
||||
.python-version
|
||||
main.py
|
||||
pyproject.toml
|
||||
README.md
|
||||
```
|
||||
|
||||
- `.git`, `.gitignore`: uv 會自動建立 git repo,但是還沒 commit。
|
||||
- `.python-version`: 這個專案使用的 Python 版本,如果你在 `uv init` 的時候沒有指定 Python 版本,那麼就會用**已安裝的最高版本**。
|
||||
- `main.py`: 你的程式
|
||||
- `pyproject.toml`: `pyproject.toml`是 [PEP 518](https://peps.python.org/pep-0518/) 與 [PEP 621](https://peps.python.org/pep-0621/) 中提出的標準,用來定義 Python 的執行環境的設定檔
|
||||
|
||||
|
||||
#### 執行檔案
|
||||
一樣用 `uv run` 就可以執行,例:`uv run main.py`。
|
||||
|
||||
在 `uv run` 執行過後,會多出一個 `uv.lock` 的檔案,這個檔案由 uv 管理(`uv add`會用到),`uv.lock` 基本上就是 `pyproject.toml` 的內容,uv 根據這個檔案來管理執行環境與套件。
|
||||
|
||||
|
||||
#### 安裝套件
|
||||
在 uv 管理的資料夾內安裝套件有2個方式,`uv pip install` 與 `uv add`。
|
||||
|
||||
|
||||
##### `uv add`
|
||||
例如我們用 `uv add` 安裝 rich 這個套件:
|
||||
```shell
|
||||
uv add rich
|
||||
```
|
||||
|
||||
uv 會幫你修改 `pyproject.toml` 與 `uv.lock`。
|
||||
|
||||
`pyproject.toml` 的內容會變成:
|
||||
```
|
||||
[project]
|
||||
name = "hello-uv"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"rich>=13.9.4",
|
||||
]
|
||||
```
|
||||
|
||||
dependencies 會多出 rich 套件以及版號。
|
||||
|
||||
而 `uv.lock` 也會同步修改,內容如下:
|
||||
```
|
||||
version = 1
|
||||
revision = 1
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "hello-uv"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "rich" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "rich", specifier = ">=13.9.4" }]
|
||||
|
||||
// 略
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.9.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
// 略
|
||||
```
|
||||
|
||||
這樣屆時你將資料夾分享出去,只要用 `uv run` 就可以了,uv 會自動安裝相應的環境與套件,很方便。
|
||||
|
||||
|
||||
##### `uv pip`
|
||||
`uv pip` 就很單純,它就是幫你裝套件而已,在 `pyproject.toml` 與 `uv.lock` 內都不會有紀錄。
|
||||
|
||||
|
||||
#### 移除套件
|
||||
使用 `uv add` 安裝的套件就用 `uv remove` 來移除。
|
||||
|
||||
使用 `uv pip install` 安裝的套件就用 `uv pip uninstall` 來移除。
|
||||
|
||||
|
||||
##### `pyproject.toml` 被修改了怎麼辦?
|
||||
先執行 `uv lock` 來將 `pyproject.toml` 的內容更新到 `uv.lock` ,再執行 `uv sync` 來更新環境與套件。
|
||||
|
||||
|
||||
### 建立虛擬環境
|
||||
專案資料夾已經建立好了,這時候如果你透過 `uv run main.py` 去執行你的 py 檔,你會發現 uv 幫你建立了一個 `.venv` 的虛擬環境。
|
||||
這個虛擬環境的 Python 版本就是當初你在 `uv init` 時所指定的版本。
|
||||
|
||||
在 Windows,你可以透過 `.venv\Script\activate.bat` 來啟動虛擬環境。
|
||||
|
||||
用 `deactivate` 來關閉虛擬環境。
|
||||
|
||||
如果你還需要其他的虛擬環境,可以用 `uv venv py311 --python 3.11` 來建立不同的虛擬環境。
|
||||
|
||||
以上面例子來說,新建立了一個 Python 3.11 的虛擬環境,資料夾名字是 `py311`。
|
||||
|
||||
你可以根據自己的需要更換資聊夾名稱。
|
||||
|
||||
要注意的是,`uv add`、`uv remove` 這些動作還是作用在一開始的版本上(也就是 `.python-version` 裡面的版本)。
|
||||
|
||||
如果要針對某一個新增的虛擬環境安裝套件的話,在啟用該虛擬環境之後,用 `uv pip install` 安裝即可。
|
||||
|
||||
以上面例子來說,如果我們要對 `py311` 這個環境新增套件(例如 [PyInstaller](https://pyinstaller.org/en/stable/)),我們要:
|
||||
1. 先啟用虛擬環境:`source py311/script/activate`。Windows 則是 `py311/script/activate.bat`
|
||||
2. 安裝:`uv pip install pyinstaller`。
|
||||
3. 離開虛擬環境:`deactivate`。
|
||||
|
||||
|
||||
## 方便的 `uv tool`
|
||||
### 安裝工具
|
||||
之前安裝的套件都是給某個檔案或是資料夾使用,但是 Python 世界裡有些套件是可以單獨使用的,像是 yt-dlp 可以在命令列當作一個工具來用:
|
||||
```
|
||||
yt-dlp https://www.youtube.com/watch?v=111
|
||||
```
|
||||
|
||||
這時候就可以用 `uv tool install yt-dlp` ,uv 會建立一個環境專供 yt-dlp ,不用怕污染到其他專案。
|
||||
安裝好之後,yt-dlp 就可以直接使用了。
|
||||
|
||||
|
||||
### 移除工具
|
||||
`uv tool uninstall <package_name>` 可以移除工具(套件)。
|
||||
|
||||
|
||||
### 更新工具
|
||||
`uv tool upgrade <package_name>` 可以更新工具(套件)。
|
||||
|
||||
|
||||
### 工具安裝位置
|
||||
`uv tool dir` 會列出工具安裝路徑。
|
||||
|
||||
|
||||
## 用 uv 執行 `.py`
|
||||
這邊的`.py` 檔是指沒有被 uv 管理的檔案,假設你拿到一個檔案 `test.py`,你可以用 uv 來指定 Python 版本與套件來執行它。
|
||||
先從最簡單的開始,例:
|
||||
```
|
||||
uv run test.py
|
||||
```
|
||||
|
||||
uv 會找一個 Python 版本來執行它。uv 挑選 Python 版本的規則是這樣:
|
||||
1. 如果目前目錄有 `.python-version`,而且裡面有版號,那就用這一版來執行。
|
||||
2. 目前已經有啟用了某個虛擬環境,那就用這個虛擬環境來執行。
|
||||
3. 目前的目錄有 `.venv` 這個資料夾,那就用`.venv` 這個資料夾裡面紀錄的版號來執行。
|
||||
4. uv 已安裝的最高版本。
|
||||
5. 目前環境有能找到的第一個 Python 執行檔。
|
||||
|
||||
當然你也可以指定一個 Python 版本來執行:
|
||||
```
|
||||
uv run --python 3.11 test.py
|
||||
```
|
||||
|
||||
如果指定的版本沒有安裝,uv 會自動安裝。
|
||||
|
||||
如果檔案裡面有需要安裝的套件,也可以寫出需要的套件,使用 `--with` 參數:
|
||||
```
|
||||
uv run --python 3.11 --with rich test.py
|
||||
```
|
||||
|
||||
uv 會建立一個臨時的虛擬環境,幫你安裝 rich 套件,並執行 `test.py`。
|
||||
|
||||
### 管理臨時的虛擬環境
|
||||
用 `uv cache dir` 列出臨時的虛擬環境的路徑。
|
||||
|
||||
用 [`uv cache clean`](https://docs.astral.sh/uv/reference/cli/#uv-cache-clean) 清除臨時的虛擬環境。
|
||||
10
deploy.sh
@@ -1,6 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
CONTAINER_DIR="/lvm1/docker/blog"
|
||||
IP_ADDR="192.168.1.24"
|
||||
|
||||
../../bin/0.100.1_extend/hugo.exe
|
||||
ssh -t root@192.168.1.30 "rm -rf /var/www/html/*"
|
||||
scp -r ./public/* root@192.168.1.30:/var/www/html/
|
||||
ssh -t root@192.168.1.30 "systemctl restart apache2"
|
||||
ssh -t awin@${IP_ADDR} "rm -rf ${CONTAINER_DIR}/data/*"
|
||||
scp -r ./public/* awin@${IP_ADDR}:${CONTAINER_DIR}/data
|
||||
ssh -t awin@${IP_ADDR} "sudo docker compose -f ${CONTAINER_DIR}/docker-compose.yml down ; sudo docker compose -f ${CONTAINER_DIR}/docker-compose.yml up -d"
|
||||
rm -rf public
|
||||
|
||||
10
deploy_pi4.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
CONTAINER_DIR="/home/awin/docker/blog"
|
||||
IP_ADDR="192.168.1.22"
|
||||
|
||||
../../bin/0.100.1_extend/hugo.exe
|
||||
ssh -t awin@${IP_ADDR} "rm -rf ${CONTAINER_DIR}/data/*"
|
||||
scp -r ./public/* awin@${IP_ADDR}:${CONTAINER_DIR}/data
|
||||
ssh -t awin@${IP_ADDR} "sudo docker compose -f ${CONTAINER_DIR}/docker-compose.yml down ; sudo docker compose -f ${CONTAINER_DIR}/docker-compose.yml up -d"
|
||||
rm -rf public
|
||||
5
layouts/shortcodes/video.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<video class="video-shortcode" preload="{{ .Get "preload" }}" controls>
|
||||
<source src="{{ .Get "src" }}" type="{{ .Get "type" }}">
|
||||
There should have been a video here but your browser does not seem
|
||||
to support it.
|
||||
</video>
|
||||
@@ -35,7 +35,7 @@ def get_year(time_str):
|
||||
|
||||
|
||||
def create_post(filepath, args):
|
||||
with open(filepath, 'w') as f:
|
||||
with open(filepath, 'w', encoding="utf-8") as f:
|
||||
f.write('---\n')
|
||||
|
||||
for key in DEFAULT_FRONT_MATTER.keys():
|
||||
@@ -70,6 +70,8 @@ def main(args):
|
||||
print("Need a title!")
|
||||
return
|
||||
|
||||
print(f'\n--------------------------------------------------------------------------------\nargs.posttitle = {args.posttitle}')
|
||||
|
||||
os.chdir('content/posts')
|
||||
dir_name = os.path.join(str(get_year(args.postdate)), args.posttitle)
|
||||
try:
|
||||
@@ -85,7 +87,7 @@ def main(args):
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-t", "--posttitle", default=None, help="The title of post.")
|
||||
parser.add_argument("-t", "--posttitle", default=None, type=str, help="The title of post.")
|
||||
parser.add_argument("-d", "--postdate", default=datetime.datetime.now().strftime('%Y-%m-%d'), help="The date of post.")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
7
pyproject.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[project]
|
||||
name = "blog-awin-one"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = []
|
||||