Skip to content

Commit aa922a9

Browse files
authored
Merge pull request #341 from DannyBen/add/git-libs
Add support for git-sourced libraries
2 parents 0058d77 + f402778 commit aa922a9

File tree

6 files changed

+172
-27
lines changed

6 files changed

+172
-27
lines changed

lib/bashly/commands/add.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ class Add < Base
1111
Specify a different libraries source. NAME can be:
1212
1313
* Path to a local libraries directory
14-
* Github repository, in the form of 'github:user/repo'
15-
* Remote git repository, in the form of 'git:clone_url.git'
14+
* GitHub (HTTPS) repository: github:user/repo[//path@ref]
15+
* GitHub (SSH) repository: github-ssh:user/repo[//path@ref]
16+
* Remote git repository: git:repo-url.git[//path@ref]
1617
USAGE
1718
option '-f --force', 'Overwrite existing files'
1819
option '-l --list', 'Show available libraries'
@@ -25,6 +26,8 @@ def run
2526
else
2627
add_lib args['LIBRARY']
2728
end
29+
30+
lib_source.cleanup if lib_source.git?
2831
end
2932

3033
private
@@ -41,8 +44,7 @@ def show_list
4144
lib_source.config.each do |key, config|
4245
usage = key
4346
usage += " #{config['usage']}" if config['usage']
44-
usage = "--source #{source} #{usage}" if source
45-
say "g`bashly add #{usage}`"
47+
say "g`#{usage}`"
4648
say word_wrap(" #{config['help']}")
4749
say ''
4850
end

lib/bashly/library_source.rb

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,83 @@
1+
require 'fileutils'
2+
13
module Bashly
24
class LibrarySource
3-
attr_reader :path
5+
attr_reader :uri
46

5-
def initialize(path = nil)
6-
@path = path || File.expand_path('libraries', __dir__)
7-
raise "Cannot find #{config_path}" unless File.exist? config_path
7+
def initialize(uri = nil)
8+
@uri = uri || File.expand_path('libraries', __dir__)
9+
transform_github_uri if /^github(:|-)/.match? @uri
810
end
911

10-
def config
11-
@config ||= YAML.properly_load_file config_path
12+
def git?
13+
/^(git|github|github-ssh):/.match? uri
1214
end
1315

14-
def config_path
15-
@config_path ||= "#{path}/libraries.yml"
16+
def config
17+
@config ||= YAML.properly_load_file config_path
1618
end
1719

1820
def libraries
1921
config.to_h do |name, spec|
2022
[name.to_sym, Library.new(path, spec)]
2123
end
2224
end
25+
26+
def config_path
27+
@config_path ||= if File.exist?("#{path}/libraries.yml")
28+
"#{path}/libraries.yml"
29+
else
30+
raise "Cannot find #{path}/libraries.yml"
31+
end
32+
end
33+
34+
def cleanup
35+
FileUtils.rm_rf(File.join(Dir.tmpdir, 'bashly-libs-*'))
36+
end
37+
38+
private
39+
40+
def path
41+
@path ||= if uri.start_with? 'git:'
42+
git_clone
43+
else
44+
uri
45+
end
46+
end
47+
48+
def git_clone
49+
dir = Dir.mktmpdir 'bashly-libs-'
50+
safe_run "git clone --depth 1 #{git_specs[:url]} #{dir}"
51+
safe_run %[git -C "#{dir}" checkout #{git_specs[:ref]}] if git_specs[:ref]
52+
53+
"#{dir}#{git_specs[:path]}"
54+
end
55+
56+
def git_specs
57+
@git_specs ||= begin
58+
parts = uri.match(%r{git:(?<url>.*\.git)(?:/)?(?<path>/[^@]+)?@?(?<ref>.*)})
59+
raise 'Invalid source' unless parts
60+
61+
url = parts[:url]
62+
raise 'Invalid git URL' unless url
63+
64+
path = parts[:path]
65+
ref = parts[:ref].empty? ? nil : parts[:ref]
66+
67+
{ url: url, path: path, ref: ref }
68+
end
69+
end
70+
71+
def safe_run(cmd)
72+
raise "Failed running command:\nm`#{cmd}`" unless system "#{cmd} > /dev/null 2>&1"
73+
end
74+
75+
def transform_github_uri
76+
if (matches = uri.match(%r{github-ssh:(?<user>[^/]+)/(?<repo>[^/]+)(?<rest>.*)}))
77+
@uri = "git:git@github.com:#{matches[:user]}/#{matches[:repo]}.git#{matches[:rest]}"
78+
elsif (matches = uri.match(%r{github:(?<user>[^/]+)/(?<repo>[^/]+)(?<rest>.*)}))
79+
@uri = "git:https://github.com/#{matches[:user]}/#{matches[:repo]}.git#{matches[:rest]}"
80+
end
81+
end
2382
end
2483
end

spec/approvals/cli/add/help

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ Options:
1010
Specify a different libraries source. NAME can be:
1111

1212
* Path to a local libraries directory
13-
* Github repository, in the form of 'github:user/repo'
14-
* Remote git repository, in the form of 'git:clone_url.git'
13+
* GitHub (HTTPS) repository: github:user/repo[//path@ref]
14+
* GitHub (SSH) repository: github-ssh:user/repo[//path@ref]
15+
* Remote git repository: git:repo-url.git[//path@ref]
1516

1617
-f --force
1718
Overwrite existing files

spec/approvals/cli/add/list

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,42 @@
1-
bashly add colors
1+
colors
22
Add standard functions for printing colorful and formatted text to the lib
33
directory.
44

5-
bashly add completions [PATH]
5+
completions [PATH]
66
Generate a bash completions function.
77

8-
bashly add completions_script [PATH]
8+
completions_script [PATH]
99
Generate a standalone bash completions script.
1010

11-
bashly add completions_yaml [PATH]
11+
completions_yaml [PATH]
1212
Generate a completions YAML configuration for Completely.
1313

14-
bashly add config
14+
config
1515
Add standard functions for handling INI files to the lib directory.
1616

17-
bashly add help
17+
help
1818
Add a help command, in addition to the standard --help flag.
1919

20-
bashly add lib
20+
lib
2121
Create the lib directory for any additional user scripts.
2222
All *.sh scripts in this directory will be included in the final bash script.
2323
Note that if you configured a different partials_extension, then the
2424
extensions of the files in this directory need to match.
2525

26-
bashly add settings
26+
settings
2727
Copy a sample settings.yml file to your project, allowing you to customize
2828
some bashly options.
2929

30-
bashly add strings
30+
strings
3131
Copy an additional configuration file to your project, allowing you to
3232
customize all the tips and error strings.
3333

34-
bashly add test
34+
test
3535
Add approval testing.
3636

37-
bashly add validations
37+
validations
3838
Add argument validation functions to the lib directory.
3939

40-
bashly add yaml
40+
yaml
4141
Add standard functions for reading YAML files.
4242

spec/approvals/cli/add/list-path

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
bashly add --source spec/fixtures/libraries database
1+
database
22
Add database utilities
33

spec/bashly/library_source_spec.rb

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,60 @@
11
require 'spec_helper'
22

33
describe LibrarySource do
4+
subject { described_class.new uri }
5+
6+
let(:uri) { nil }
7+
8+
after(:all) { described_class.new.cleanup }
9+
10+
describe '#uri' do
11+
context 'when it starts with github:' do
12+
let(:uri) { 'github:user/repo//the-path@the-ref' }
13+
14+
it 'is transformed to git over https' do
15+
expect(subject.uri).to eq 'git:https://github.com/user/repo.git//the-path@the-ref'
16+
end
17+
end
18+
19+
context 'when it starts with github-ssh:' do
20+
let(:uri) { 'github-ssh:user/repo//the-path@the-ref' }
21+
22+
it 'is transformed to git over ssh' do
23+
expect(subject.uri).to eq 'git:git@github.com:user/repo.git//the-path@the-ref'
24+
end
25+
end
26+
end
27+
28+
describe '#git?' do
29+
it 'returns false' do
30+
expect(subject).not_to be_git
31+
end
32+
33+
context 'when the uri starts with git:' do
34+
let(:uri) { 'git:/repo' }
35+
36+
it 'returns true' do
37+
expect(subject).to be_git
38+
end
39+
end
40+
41+
context 'when the uri starts with github:' do
42+
let(:uri) { 'github:/repo' }
43+
44+
it 'returns true' do
45+
expect(subject).to be_git
46+
end
47+
end
48+
49+
context 'when the uri starts with github-ssh:' do
50+
let(:uri) { 'github-ssh:/repo' }
51+
52+
it 'returns true' do
53+
expect(subject).to be_git
54+
end
55+
end
56+
end
57+
458
describe '#config' do
559
it 'returns the contents of the libraries.yml file' do
660
expect(subject.config).to be_a Hash
@@ -19,6 +73,28 @@
1973
end
2074
end
2175

76+
describe '#config_path' do
77+
it 'returns the path to libraries.yml' do
78+
expect(subject.config_path).to eq "#{subject.uri}/libraries.yml"
79+
end
80+
81+
context 'with a git source' do
82+
let(:uri) { 'github:dannyben/bashly//spec/fixtures/libraries@0058d77' }
83+
84+
it 'clones the repo to a temp directory and returns its path' do
85+
expect(subject.config_path).to match %r{/tmp/bashly-libs-.*/spec/fixtures/libraries/libraries.yml}
86+
end
87+
end
88+
89+
context 'with a directory that does not contain libraries.yml' do
90+
let(:uri) { 'spec' }
91+
92+
it 'raises an error' do
93+
expect { subject.config_path }.to raise_error('Cannot find spec/libraries.yml')
94+
end
95+
end
96+
end
97+
2298
describe '#libraries' do
2399
it 'returns a hash' do
24100
expect(subject.libraries).to be_a Hash
@@ -35,4 +111,11 @@
35111
expect(subject.libraries.values.map(&:class).uniq).to eq [Library]
36112
end
37113
end
114+
115+
describe '#cleanup' do
116+
it 'remoces all /tmp/bashly-libs-* directories' do
117+
expect(FileUtils).to receive(:rm_rf).with("#{Dir.tmpdir}/bashly-libs-*")
118+
subject.cleanup
119+
end
120+
end
38121
end

0 commit comments

Comments
 (0)