Files
omarchy-pkgs/pkgbuilds/rime-ice-installer/omarchy-offline.patch
T

321 lines
11 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
diff --git a/internal/app/app.go b/internal/app/app.go
index 17e01bf..fd73578 100644
--- a/internal/app/app.go
+++ b/internal/app/app.go
@@ -84,7 +84,8 @@ func Run(ctx context.Context, cfg config.InstallConfig) error {
return err
}
- if os.Geteuid() != 0 {
+ missingPackages := fcitx.MissingPackages()
+ if os.Geteuid() != 0 && len(missingPackages) > 0 {
if dialogUI != nil {
if err := validateSudoWithDialog(ctx, runner, dialogUI, detectedEnv.FingerprintAvailable); err != nil {
if errors.Is(err, ui.ErrCancelled) {
@@ -140,7 +141,7 @@ func Run(ctx context.Context, cfg config.InstallConfig) error {
}
if err := step("安装 Fcitx5 与依赖", func() error {
- return fcitx.InstallPackages(ctx, runner, cfg, detectedEnv)
+ return fcitx.InstallPackages(ctx, runner, missingPackages, detectedEnv)
}); err != nil {
closeGauge(gauge)
return fail(dialogUI, logger, err)
@@ -181,7 +182,7 @@ func Run(ctx context.Context, cfg config.InstallConfig) error {
if err := step("下载并补丁雾凇拼音", func() error {
var err error
- rimeWorkspace, err = rime.PrepareWorkspace(ctx, downloader, cfg.WorkspaceDir)
+ rimeWorkspace, err = rime.PrepareWorkspace(ctx, downloader, cfg.WorkspaceDir, cfg.AssetDir)
return err
}); err != nil {
closeGauge(gauge)
@@ -191,7 +192,7 @@ func Run(ctx context.Context, cfg config.InstallConfig) error {
if cfg.EnableWanxiang {
if err := step("下载并启用万象语法模型", func() error {
var err error
- modelRelease, err = wanxiang.Integrate(ctx, downloader, cfg.WorkspaceDir, rimeWorkspace.SourceDir)
+ modelRelease, err = wanxiang.Integrate(ctx, downloader, cfg.WorkspaceDir, rimeWorkspace.SourceDir, cfg.AssetDir)
return err
}); err != nil {
closeGauge(gauge)
diff --git a/internal/config/config.go b/internal/config/config.go
index e3554e8..2efc8c2 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -18,6 +18,7 @@ type InstallConfig struct {
DryRun bool
Verbose bool
WorkspaceDir string
+ AssetDir string
}
type DetectedEnv struct {
diff --git a/internal/fcitx/fcitx.go b/internal/fcitx/fcitx.go
index fba202a..f252ca1 100644
--- a/internal/fcitx/fcitx.go
+++ b/internal/fcitx/fcitx.go
@@ -34,10 +34,23 @@ const (
defaultGroupName = "Default"
)
-func InstallPackages(ctx context.Context, runner *system.Runner, cfg config.InstallConfig, env config.DetectedEnv) error {
- args := append([]string{"-S", "--needed", "--noconfirm"}, pacmanPackages...)
- if err := runner.RunPrivileged(ctx, "pacman", args...); err != nil {
- return err
+// MissingPackages 返回尚未安装的 pacman 包。
+func MissingPackages() []string {
+ var missing []string
+ for _, pkg := range pacmanPackages {
+ if exec.Command("pacman", "-Q", pkg).Run() != nil {
+ missing = append(missing, pkg)
+ }
+ }
+ return missing
+}
+
+func InstallPackages(ctx context.Context, runner *system.Runner, missing []string, env config.DetectedEnv) error {
+ if len(missing) > 0 {
+ args := append([]string{"-S", "--needed", "--noconfirm"}, missing...)
+ if err := runner.RunPrivileged(ctx, "pacman", args...); err != nil {
+ return err
+ }
}
if !env.HasOctagramPlugin {
diff --git a/internal/rime/asset_dir_test.go b/internal/rime/asset_dir_test.go
new file mode 100644
index 0000000..9e66346
--- /dev/null
+++ b/internal/rime/asset_dir_test.go
@@ -0,0 +1,49 @@
+package rime
+
+import (
+ "archive/zip"
+ "context"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestPrepareWorkspaceReadsFullZipFromAssetDir(t *testing.T) {
+ assetDir := t.TempDir()
+ archive, err := os.Create(filepath.Join(assetDir, rimeIceAsset))
+ if err != nil {
+ t.Fatal(err)
+ }
+ writer := zip.NewWriter(archive)
+ entry, err := writer.Create("rime_ice.schema.yaml")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := entry.Write([]byte("schema:\n schema_id: rime_ice\n")); err != nil {
+ t.Fatal(err)
+ }
+ if err := writer.Close(); err != nil {
+ t.Fatal(err)
+ }
+ archive.Close()
+
+ workspace := t.TempDir()
+ prepared, err := PrepareWorkspace(context.Background(), nil, workspace, assetDir)
+ if err != nil {
+ t.Fatalf("PrepareWorkspace() error = %v", err)
+ }
+ if prepared.Release.Tag != "local" || prepared.Release.AssetName != rimeIceAsset {
+ t.Fatalf("release = %+v, want local %s", prepared.Release, rimeIceAsset)
+ }
+ for _, name := range []string{"rime_ice.schema.yaml", "default.custom.yaml", "user.yaml"} {
+ if _, err := os.Stat(filepath.Join(prepared.SourceDir, name)); err != nil {
+ t.Fatalf("%s missing from prepared workspace: %v", name, err)
+ }
+ }
+}
+
+func TestPrepareWorkspaceFailsWithoutLocalFullZip(t *testing.T) {
+ if _, err := PrepareWorkspace(context.Background(), nil, t.TempDir(), t.TempDir()); err == nil {
+ t.Fatal("PrepareWorkspace() succeeded without full.zip in the asset dir")
+ }
+}
diff --git a/internal/rime/rime.go b/internal/rime/rime.go
index 1db520b..45900be 100644
--- a/internal/rime/rime.go
+++ b/internal/rime/rime.go
@@ -26,20 +26,28 @@ type PreparedWorkspace struct {
Release config.ReleaseInfo
}
-func PrepareWorkspace(ctx context.Context, client *download.Client, workspace string) (*PreparedWorkspace, error) {
- release, err := client.ReleaseByTag(ctx, rimeIceOwner, rimeIceRepo, rimeIceTag)
- if err != nil {
- return nil, err
- }
+func PrepareWorkspace(ctx context.Context, client *download.Client, workspace, assetDir string) (*PreparedWorkspace, error) {
+ info := config.ReleaseInfo{Owner: rimeIceOwner, Repo: rimeIceRepo, Tag: "local", AssetName: rimeIceAsset}
+ downloadPath := filepath.Join(assetDir, rimeIceAsset)
+ if assetDir == "" {
+ release, err := client.ReleaseByTag(ctx, rimeIceOwner, rimeIceRepo, rimeIceTag)
+ if err != nil {
+ return nil, err
+ }
- asset, err := download.FindAsset(release, rimeIceAsset)
- if err != nil {
- return nil, err
- }
+ asset, err := download.FindAsset(release, rimeIceAsset)
+ if err != nil {
+ return nil, err
+ }
- downloadPath := filepath.Join(workspace, "downloads", asset.Name)
- if err := client.DownloadAsset(ctx, asset, downloadPath); err != nil {
- return nil, err
+ downloadPath = filepath.Join(workspace, "downloads", asset.Name)
+ if err := client.DownloadAsset(ctx, asset, downloadPath); err != nil {
+ return nil, err
+ }
+ info.Tag = release.TagName
+ info.AssetName = asset.Name
+ info.Digest = normalizeDigest(asset.Digest)
+ info.URL = asset.BrowserDownloadURL
}
sourceDir := filepath.Join(workspace, "source", "rime-ice")
@@ -54,17 +62,7 @@ func PrepareWorkspace(ctx context.Context, client *download.Client, workspace st
return nil, err
}
- return &PreparedWorkspace{
- SourceDir: sourceDir,
- Release: config.ReleaseInfo{
- Owner: rimeIceOwner,
- Repo: rimeIceRepo,
- Tag: release.TagName,
- AssetName: asset.Name,
- Digest: normalizeDigest(asset.Digest),
- URL: asset.BrowserDownloadURL,
- },
- }, nil
+ return &PreparedWorkspace{SourceDir: sourceDir, Release: info}, nil
}
func MergeDefaultCustomConfig(path string) error {
diff --git a/internal/wanxiang/asset_dir_test.go b/internal/wanxiang/asset_dir_test.go
new file mode 100644
index 0000000..23554b3
--- /dev/null
+++ b/internal/wanxiang/asset_dir_test.go
@@ -0,0 +1,33 @@
+package wanxiang
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func TestIntegrateReadsModelFromAssetDir(t *testing.T) {
+ assetDir := t.TempDir()
+ if err := os.WriteFile(filepath.Join(assetDir, modelAsset), []byte("model"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ sourceDir := t.TempDir()
+ info, err := Integrate(context.Background(), nil, t.TempDir(), sourceDir, assetDir)
+ if err != nil {
+ t.Fatalf("Integrate() error = %v", err)
+ }
+ if info.Tag != "local" || info.AssetName != modelAsset {
+ t.Fatalf("release = %+v, want local %s", info, modelAsset)
+ }
+ model, err := os.ReadFile(filepath.Join(sourceDir, modelAsset))
+ if err != nil || string(model) != "model" {
+ t.Fatalf("model copy = %q, %v", model, err)
+ }
+ custom, err := os.ReadFile(filepath.Join(sourceDir, "rime_ice.custom.yaml"))
+ if err != nil || !strings.Contains(string(custom), "wanxiang-lts-zh-hans") {
+ t.Fatalf("custom yaml = %q, %v", custom, err)
+ }
+}
diff --git a/internal/wanxiang/wanxiang.go b/internal/wanxiang/wanxiang.go
index f629977..a0fd266 100644
--- a/internal/wanxiang/wanxiang.go
+++ b/internal/wanxiang/wanxiang.go
@@ -21,23 +21,31 @@ const (
modelAsset = "wanxiang-lts-zh-hans.gram"
)
-func Integrate(ctx context.Context, client *download.Client, workspace, sourceDir string) (*config.ReleaseInfo, error) {
- release, err := client.ReleaseByTag(ctx, modelOwner, modelRepo, modelTag)
- if err != nil {
- return nil, err
- }
+func Integrate(ctx context.Context, client *download.Client, workspace, sourceDir, assetDir string) (*config.ReleaseInfo, error) {
+ info := &config.ReleaseInfo{Owner: modelOwner, Repo: modelRepo, Tag: "local", AssetName: modelAsset}
+ downloadPath := filepath.Join(assetDir, modelAsset)
+ if assetDir == "" {
+ release, err := client.ReleaseByTag(ctx, modelOwner, modelRepo, modelTag)
+ if err != nil {
+ return nil, err
+ }
- asset, err := download.FindAsset(release, modelAsset)
- if err != nil {
- return nil, err
- }
+ asset, err := download.FindAsset(release, modelAsset)
+ if err != nil {
+ return nil, err
+ }
- downloadPath := filepath.Join(workspace, "downloads", asset.Name)
- if err := client.DownloadAsset(ctx, asset, downloadPath); err != nil {
- return nil, err
+ downloadPath = filepath.Join(workspace, "downloads", asset.Name)
+ if err := client.DownloadAsset(ctx, asset, downloadPath); err != nil {
+ return nil, err
+ }
+ info.Tag = release.TagName
+ info.AssetName = asset.Name
+ info.Digest = strings.TrimPrefix(asset.Digest, "sha256:")
+ info.URL = asset.BrowserDownloadURL
}
- targetModelPath := filepath.Join(sourceDir, asset.Name)
+ targetModelPath := filepath.Join(sourceDir, modelAsset)
modelContent, err := os.ReadFile(downloadPath)
if err != nil {
return nil, fmt.Errorf("读取模型文件失败: %w", err)
@@ -50,14 +58,7 @@ func Integrate(ctx context.Context, client *download.Client, workspace, sourceDi
return nil, err
}
- return &config.ReleaseInfo{
- Owner: modelOwner,
- Repo: modelRepo,
- Tag: release.TagName,
- AssetName: asset.Name,
- Digest: strings.TrimPrefix(asset.Digest, "sha256:"),
- URL: asset.BrowserDownloadURL,
- }, nil
+ return info, nil
}
func MergeCustomConfig(path string) error {
diff --git a/main.go b/main.go
index 50f00f3..15439bd 100644
--- a/main.go
+++ b/main.go
@@ -19,6 +19,7 @@ func main() {
flag.BoolVar(&cfg.EnableWanxiang, "enable-wanxiang", cfg.EnableWanxiang, "下载并启用万象 LTS 语法模型")
flag.IntVar(&cfg.FontSize, "font-size", cfg.FontSize, "Fcitx5 候选框字体大小(8-48)")
flag.StringVar(&cfg.WorkspaceDir, "workspace-dir", cfg.WorkspaceDir, "工作目录,用于下载缓存和日志")
+ flag.StringVar(&cfg.AssetDir, "asset-dir", "", "从此目录读取 full.zip 和万象模型,不访问 GitHub")
flag.Parse()
if err := app.Run(context.Background(), cfg); err != nil {