Class: MilkTea::PackageRegistryStore

Inherits:
Object
  • Object
show all
Defined in:
lib/milk_tea/packages/registry_store.rb

Defined Under Namespace

Classes: Result

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root: self.class.default_root, upstream_root: self.class.default_upstream_root) ⇒ PackageRegistryStore

Returns a new instance of PackageRegistryStore.



48
49
50
51
# File 'lib/milk_tea/packages/registry_store.rb', line 48

def initialize(root: self.class.default_root, upstream_root: self.class.default_upstream_root)
  @root = File.expand_path(root)
  @upstream_root = normalize_optional_root(upstream_root)
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



46
47
48
# File 'lib/milk_tea/packages/registry_store.rb', line 46

def root
  @root
end

#upstream_rootObject (readonly)

Returns the value of attribute upstream_root.



46
47
48
# File 'lib/milk_tea/packages/registry_store.rb', line 46

def upstream_root
  @upstream_root
end

Class Method Details

.default_root(env: ENV, home: nil) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/milk_tea/packages/registry_store.rb', line 18

def self.default_root(env: ENV, home: nil)
  explicit_root = env.fetch("MILK_TEA_PACKAGE_REGISTRY", "").to_s.strip
  return File.expand_path(explicit_root) unless explicit_root.empty?

  xdg_data_home = env.fetch("XDG_DATA_HOME", "").to_s.strip
  base_root = if xdg_data_home.empty?
                File.join(home || Dir.home, ".local", "share")
              else
                File.expand_path(xdg_data_home)
              end

  File.join(base_root, "milk_tea", "registry")
end

.default_upstream_root(env: ENV) ⇒ Object



32
33
34
35
36
37
# File 'lib/milk_tea/packages/registry_store.rb', line 32

def self.default_upstream_root(env: ENV)
  explicit_root = env.fetch("MILK_TEA_PACKAGE_REGISTRY_UPSTREAM", "").to_s.strip
  return nil if explicit_root.empty?

  http_url?(explicit_root) ? explicit_root : File.expand_path(explicit_root)
end

.http_url?(value) ⇒ Boolean

Returns:

  • (Boolean)


39
40
41
42
43
44
# File 'lib/milk_tea/packages/registry_store.rb', line 39

def self.http_url?(value)
  uri = URI.parse(value.to_s)
  %w[http https].include?(uri.scheme)
rescue URI::InvalidURIError
  false
end

Instance Method Details

#available_versions(package_name) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/milk_tea/packages/registry_store.rb', line 79

def available_versions(package_name)
  versions = package_versions_for_root(@root, package_name)
  if upstream_configured?
    upstream_versions = if upstream_http?
                          package_versions_for_http(package_name)
                        else
                          package_versions_for_root(@upstream_root, package_name)
                        end
    versions = upstream_versions + versions
  end

  versions.uniq
end

#manifest_path_for(package_or_identity, version = nil) ⇒ Object



59
60
61
# File 'lib/milk_tea/packages/registry_store.rb', line 59

def manifest_path_for(package_or_identity, version = nil)
  File.join(package_root_for(package_or_identity, version), "package.toml")
end

#package_root_for(package_or_identity, version = nil) ⇒ Object



53
54
55
56
57
# File 'lib/milk_tea/packages/registry_store.rb', line 53

def package_root_for(package_or_identity, version = nil)
  package_name, package_version = extract_package_version(package_or_identity, version)

  File.join(@root, "packages", normalize_component(package_name, "package name"), normalize_component(package_version, "package version"))
end

#publish(path, target: :local) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/milk_tea/packages/registry_store.rb', line 93

def publish(path, target: :local)
  manifest = PackageManifest.load(path)
  package_version = manifest.package_version.to_s.strip
  if package_version.empty?
    raise PackageRegistryStoreError,
          "package #{manifest.package_name} at #{manifest.manifest_path} must declare package.version before publishing"
  end

  target_root = registry_root_for_target(target)
  package_root = package_root_for_root(target_root, manifest.package_name, package_version)
  if File.exist?(package_root)
    raise PackageRegistryStoreError,
          "package #{manifest.package_name} version #{package_version} already published in registry: #{package_root}"
  end

  materialize_package_copy!(manifest.root_dir, package_root)
  write_registry_artifacts_with_rollback!(target_root, manifest.package_name, package_version, package_root)

  Result.new(package_name: manifest.package_name, version: package_version, path: package_root)
rescue PackageManifestError => e
  raise PackageRegistryStoreError, e.message
rescue SystemCallError => e
  raise PackageRegistryStoreError, "failed to publish package to #{target_root || @root}: #{e.message}"
end

#published?(package_or_identity, version = nil) ⇒ Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/milk_tea/packages/registry_store.rb', line 63

def published?(package_or_identity, version = nil)
  File.file?(manifest_path_for(package_or_identity, version))
end

#published_root_for(package_or_identity, version = nil, sync: false) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/milk_tea/packages/registry_store.rb', line 67

def published_root_for(package_or_identity, version = nil, sync: false)
  package_name, package_version = extract_package_version(package_or_identity, version)
  sync(package_name, package_version) if sync && !published?(package_name, package_version) && upstream_configured?
  manifest_path = manifest_path_for(package_name, package_version)
  unless File.file?(manifest_path)
    raise PackageRegistryStoreError,
          "registry package #{package_name} version #{package_version} not found in #{@root}"
  end

  package_root_for(package_name, package_version)
end

#sync(package_or_identity, version = nil) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/milk_tea/packages/registry_store.rb', line 118

def sync(package_or_identity, version = nil)
  package_name, package_version = extract_package_version(package_or_identity, version)
  raise PackageRegistryStoreError, "registry upstream is not configured" unless upstream_configured?

  local_root = package_root_for(package_name, package_version)
  return Result.new(package_name:, version: package_version, path: local_root) if published?(package_name, package_version)

  return sync_from_http(package_name, package_version, local_root) if upstream_http?

  upstream_package_root = package_root_for_root(@upstream_root, package_name, package_version)
  upstream_manifest_path = File.join(upstream_package_root, "package.toml")
  unless File.file?(upstream_manifest_path)
    raise PackageRegistryStoreError,
          "registry package #{package_name} version #{package_version} not found in upstream registry #{@upstream_root}"
  end

  upstream_manifest = PackageManifest.load(upstream_package_root)
  if upstream_manifest.package_name != package_name || upstream_manifest.package_version != package_version
    raise PackageRegistryStoreError,
          "upstream registry package at #{upstream_manifest.manifest_path} resolved to #{upstream_manifest.package_name}@#{upstream_manifest.package_version.inspect}; expected #{package_name}@#{package_version}"
  end

  materialize_package_copy!(upstream_package_root, local_root)
  write_registry_artifacts_with_rollback!(@root, package_name, package_version, local_root)

  Result.new(package_name:, version: package_version, path: local_root)
rescue PackageManifestError => e
  raise PackageRegistryStoreError, e.message
rescue SystemCallError => e
  raise PackageRegistryStoreError, "failed to sync package from upstream registry #{@upstream_root}: #{e.message}"
end

#upstream_configured?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/milk_tea/packages/registry_store.rb', line 150

def upstream_configured?
  !@upstream_root.nil?
end

#upstream_http?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/milk_tea/packages/registry_store.rb', line 154

def upstream_http?
  self.class.http_url?(@upstream_root)
end