Skip to content

Commit f6b9fff

Browse files
authored
Merge pull request #854 from pocke/collection-local-directory-source
Add local source for rbs collection
2 parents c5d869b + 093956f commit f6b9fff

File tree

15 files changed

+431
-14
lines changed

15 files changed

+431
-14
lines changed

docs/collection.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ sources:
7979
revision: main
8080
repo_dir: gems
8181

82+
# You can also add a local path as a collection source optionaly.
83+
- type: local
84+
path: path/to/local/dir
85+
8286
# A directory to install the downloaded RBSs
8387
path: .gem_rbs_collection
8488

lib/rbs/cli.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,11 +1076,16 @@ def run_collection(args, options)
10761076
config_path.write(<<~'YAML')
10771077
# Download sources
10781078
sources:
1079-
- name: ruby/gem_rbs_collection
1079+
- type: git
1080+
name: ruby/gem_rbs_collection
10801081
remote: https://github.com/ruby/gem_rbs_collection.git
10811082
revision: main
10821083
repo_dir: gems
10831084
1085+
# You can specify local directories as sources also.
1086+
# - type: local
1087+
# path: path/to/your/local/repository
1088+
10841089
# A directory to install the downloaded RBSs
10851090
path: .gem_rbs_collection
10861091

lib/rbs/collection/cleaner.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@ def clean
1616
version or raise
1717
next if needed? gem_name, version
1818

19-
FileUtils.remove_entry_secure(dir.to_s)
19+
case
20+
when dir.symlink?
21+
dir.unlink
22+
when dir.directory?
23+
FileUtils.remove_entry_secure(dir.to_s)
24+
else
25+
raise
26+
end
2027
end
2128
end
2229

lib/rbs/collection/config.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def repo_path_data
6666
def sources
6767
@sources ||= (
6868
@data['sources']
69-
.map { |c| Sources.from_config_entry(c) }
69+
.map { |c| Sources.from_config_entry(c, base_directory: @config_path.dirname) }
7070
.push(Sources::Stdlib.instance)
7171
.push(Sources::Rubygems.instance)
7272
)

lib/rbs/collection/config/lockfile.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def self.from_lockfile(lockfile_path:, data:)
7575
if gems = data["gems"]
7676
gems.each do |gem|
7777
src = gem["source"]
78-
source = Sources.from_config_entry(src)
78+
source = Sources.from_config_entry(src, base_directory: lockfile_path.dirname)
7979
lockfile.gems[gem["name"]] = {
8080
name: gem["name"],
8181
version: gem["version"],
@@ -106,6 +106,8 @@ def check_rbs_availability!
106106
meta_path = fullpath.join(gem[:name], gem[:version], Sources::Git::METADATA_FILENAME)
107107
raise CollectionNotAvailable unless meta_path.exist?
108108
raise CollectionNotAvailable unless library_data(gem) == YAML.load(meta_path.read)
109+
when Sources::Local
110+
raise CollectionNotAvailable unless fullpath.join(gem[:name], gem[:version]).symlink?
109111
end
110112
end
111113
end

lib/rbs/collection/config/lockfile_generator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def generate
105105
unless locked
106106
source =
107107
if src_data
108-
Sources.from_config_entry(src_data)
108+
Sources.from_config_entry(src_data, base_directory: config.config_path.dirname)
109109
else
110110
find_source(name: name)
111111
end

lib/rbs/collection/sources.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
require_relative './sources/git'
55
require_relative './sources/stdlib'
66
require_relative './sources/rubygems'
7+
require_relative './sources/local'
78

89
module RBS
910
module Collection
1011
module Sources
11-
def self.from_config_entry(source_entry)
12+
def self.from_config_entry(source_entry, base_directory:)
1213
case source_entry['type']
1314
when 'git', nil # git source by default
1415
# @type var source_entry: Git::source_entry
@@ -18,6 +19,12 @@ def self.from_config_entry(source_entry)
1819
remote: source_entry["remote"],
1920
repo_dir: source_entry["repo_dir"]
2021
)
22+
when 'local'
23+
# @type var source_entry: Local::source_entry
24+
Local.new(
25+
path: source_entry['path'],
26+
base_directory: base_directory,
27+
)
2128
when 'stdlib'
2229
Stdlib.instance
2330
when 'rubygems'

lib/rbs/collection/sources/git.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ def install(dest:, name:, version:, stdout:)
4545

4646
gem_dir = dest.join(name, version)
4747

48-
if gem_dir.directory?
48+
case
49+
when gem_dir.symlink?
50+
stdout.puts "Updating to #{format_config_entry(name, version)} from a local source"
51+
gem_dir.unlink
52+
_install(dest: dest, name: name, version: version)
53+
when gem_dir.directory?
4954
prev = load_metadata(dir: gem_dir)
5055

5156
if prev == metadata_content(name: name, version: version)
@@ -55,9 +60,11 @@ def install(dest:, name:, version:, stdout:)
5560
FileUtils.remove_entry_secure(gem_dir.to_s)
5661
_install(dest: dest, name: name, version: version)
5762
end
58-
else
63+
when !gem_dir.exist?
5964
stdout.puts "Installing #{format_config_entry(name, version)}"
6065
_install(dest: dest, name: name, version: version)
66+
else
67+
raise
6168
end
6269
end
6370

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# frozen_string_literal: true
2+
3+
module RBS
4+
module Collection
5+
module Sources
6+
class Local
7+
include Base
8+
9+
attr_reader :path, :full_path
10+
11+
def initialize(path:, base_directory:)
12+
# TODO: resolve relative path from dir of rbs_collection.yaml
13+
@path = Pathname(path)
14+
@full_path = base_directory / path
15+
end
16+
17+
def has?(name, version)
18+
if version
19+
@full_path.join(name, version).directory?
20+
else
21+
not versions(name).empty?
22+
end
23+
end
24+
25+
def versions(name)
26+
@full_path.join(name).glob('*/').map { |path| path.basename.to_s }
27+
end
28+
29+
# Create a symlink instead of copying file to refer files in @path.
30+
# By avoiding copying RBS files, the users do not need re-run `rbs collection install`
31+
# when the RBS files are updated.
32+
def install(dest:, name:, version:, stdout:)
33+
from = @full_path.join(name, version)
34+
gem_dir = dest.join(name, version)
35+
36+
case
37+
when gem_dir.symlink? && gem_dir.readlink == from
38+
stdout.puts "Using #{name}:#{version} (#{from})"
39+
when gem_dir.symlink?
40+
prev = gem_dir.readlink
41+
gem_dir.unlink
42+
_install(from, dest.join(name, version))
43+
stdout.puts "Updating #{name}:#{version} to #{from} from #{prev}"
44+
when gem_dir.directory?
45+
# TODO: Show version of git source
46+
FileUtils.remove_entry_secure(gem_dir.to_s)
47+
_install(from, dest.join(name, version))
48+
stdout.puts "Updating #{name}:#{version} from git source"
49+
when !gem_dir.exist?
50+
_install(from, dest.join(name, version))
51+
stdout.puts "Installing #{name}:#{version} (#{from})"
52+
else
53+
raise
54+
end
55+
end
56+
57+
private def _install(src, dst)
58+
dst.dirname.mkpath
59+
File.symlink(src, dst)
60+
end
61+
62+
def manifest_of(name, version)
63+
gem_dir = @full_path.join(name, version)
64+
raise unless gem_dir.exist?
65+
66+
manifest_path = gem_dir.join('manifest.yaml')
67+
YAML.safe_load(manifest_path.read) if manifest_path.exist?
68+
end
69+
70+
def to_lockfile
71+
{
72+
'type' => 'local',
73+
'path' => @path.to_s,
74+
}
75+
end
76+
end
77+
end
78+
end
79+
end

sig/collection/sources.rbs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
module RBS
22
module Collection
33
module Sources
4-
def self.from_config_entry: (Git::source_entry) -> Git
5-
| (source_entry) -> t
4+
def self.from_config_entry: (Git::source_entry, base_directory: Pathname) -> Git
5+
| (source_entry, base_directory: Pathname) -> t
66

77
interface _Source
88
def has?: (String name, String? version) -> boolish
@@ -13,11 +13,12 @@ module RBS
1313
def dependencies_of: (String name, String version) -> Array[manifest_dependency]?
1414
end
1515

16-
type t = Git | Stdlib | Rubygems
16+
type t = Git | Stdlib | Rubygems | Local
1717

1818
type source_entry = Git::source_entry
1919
| Stdlib::source_entry
2020
| Rubygems::source_entry
21+
| Local::source_entry
2122

2223
type manifest_entry = {
2324
"dependencies" => Array[manifest_dependency]?,
@@ -126,6 +127,34 @@ module RBS
126127
def gems_versions: () -> Hash[String, Set[String]]
127128
end
128129

130+
class Local
131+
include Base
132+
133+
type source_entry = {
134+
'type' => 'local',
135+
'path' => String,
136+
}
137+
138+
attr_reader path: Pathname
139+
attr_reader full_path: Pathname
140+
141+
def initialize: (path: String, base_directory: Pathname) -> void
142+
143+
def has?: (String name, String? version) -> boolish
144+
145+
def versions: (String name) -> Array[String]
146+
147+
def install: (dest: Pathname, name: String, version: String, stdout: CLI::_IO) -> void
148+
149+
def to_lockfile: () -> source_entry
150+
151+
def manifest_of: (String name, String version) -> manifest_entry?
152+
153+
private
154+
155+
def _install: (Pathname src, Pathname dest) -> void
156+
end
157+
129158
# signatures that are bundled in rbs gem under the stdlib/ directory
130159
class Stdlib
131160

0 commit comments

Comments
 (0)