Module: Rubyx::Uv

Defined in:
lib/rubyx/uv.rb,
lib/rubyx/error.rb

Defined Under Namespace

Classes: Error, InitError, SetupError

Constant Summary collapse

DEFAULT_UV_VERSION =
'0.10.2'.freeze

Class Method Summary collapse

Class Method Details

.init(pyproject_toml, uv_version: DEFAULT_UV_VERSION, project_dir: nil) ⇒ Hash

Parse pyvenv.cfg, resolve platform paths, and call Rubyx.init.

Parameters:

  • pyproject_toml (String)

    Content of pyproject.toml (used to resolve project_dir)

  • uv_version (String) (defaults to: DEFAULT_UV_VERSION)

    Version of uv (used to resolve project_dir)

  • project_dir (String, Symbol, nil) (defaults to: nil)

    Same as setup

Returns:

  • (Hash)

    Resolved paths (:root_dir, :project_dir, :python_dl, etc.)

Raises:



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rubyx/uv.rb', line 67

def init(pyproject_toml, uv_version: DEFAULT_UV_VERSION, project_dir: nil)
  proj_dir = resolve_project_dir(pyproject_toml, uv_version, project_dir)

  venv_dir = File.join(proj_dir, '.venv')
  raise InitError, "Not set up. Call Rubyx::Uv.setup first." unless Dir.exist?(venv_dir)

  cfg_path = File.join(venv_dir, 'pyvenv.cfg')
  raise InitError, "pyvenv.cfg not found at #{cfg_path}" unless File.exist?(cfg_path)

  pyvenv_cfg = File.read(cfg_path)
  home_line = pyvenv_cfg.lines.find { |l| l.start_with?('home = ') }
  raise InitError, "Could not find 'home' in pyvenv.cfg" unless home_line

  home_path = home_line.sub('home = ', '').strip
  root_dir = File.dirname(home_path) # Parent of bin/

  paths = platform_paths(root_dir, proj_dir)
  validate_paths!(paths)

  sys_paths = []
  sys_paths << paths[:venv_packages] if paths[:venv_packages]
  sys_paths << proj_dir if project_dir && project_dir != :cache

  # Call the Rust init
  Rubyx.init(
    paths[:python_dl],
    paths[:python_home],
    paths[:python_exe],
    sys_paths
  )

  { root_dir: root_dir, project_dir: proj_dir, **paths }
end

.setup(pyproject_toml, force: false, uv_version: DEFAULT_UV_VERSION, project_dir: nil, uv_args: [], uv_path: nil) ⇒ String

Download uv (if needed), write pyproject.toml, and run ‘uv sync`.

Parameters:

  • pyproject_toml (String)

    Content of pyproject.toml

  • force (Boolean) (defaults to: false)

    Force re-setup even if .venv exists

  • uv_version (String) (defaults to: DEFAULT_UV_VERSION)

    Version of uv to download

  • project_dir (String, Symbol, nil) (defaults to: nil)

    Where to create the project

    • nil: use Dir.pwd

    • :cache: use a hash-based cache directory

    • String: use the specified path

  • uv_args (Array<String>) (defaults to: [])

    Extra arguments to pass to ‘uv sync`

  • uv_path (String, nil) (defaults to: nil)

    Path to an existing uv binary. When set, auto-download is skipped entirely.

Returns:

  • (String)

    The resolved project directory path



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rubyx/uv.rb', line 26

def setup(pyproject_toml, force: false, uv_version: DEFAULT_UV_VERSION,
          project_dir: nil, uv_args: [], uv_path: nil)
  proj_dir = resolve_project_dir(pyproject_toml, uv_version, project_dir)

  venv_dir = File.join(proj_dir, '.venv')
  pyproject_path = File.join(proj_dir, 'pyproject.toml')

  needs_setup = force || !Dir.exist?(venv_dir)

  if !needs_setup && File.exist?(pyproject_path)
    needs_setup = File.read(pyproject_path).strip != pyproject_toml.strip
  end

  if needs_setup
    FileUtils.rm_rf(venv_dir) if force
    FileUtils.mkdir_p(proj_dir)
    File.write(pyproject_path, pyproject_toml)

    success = run_uv!(
      ['sync', '--managed-python', '--no-config', '--project', proj_dir, *uv_args],
      chdir: proj_dir,
      env: { 'UV_PYTHON_INSTALL_DIR' => python_install_dir(uv_version) },
      uv_version: uv_version,
      uv_path: uv_path
    )

    unless success
      FileUtils.rm_rf(venv_dir)
      raise SetupError, 'uv sync failed to setup Python environment'
    end
  end

  proj_dir
end