giternal-digarc 0.1.1Digarc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,105 @@
1
+ class GiternalHelper
2
+ @@giternal_base ||= File.expand_path(File.dirname(__FILE__))
3
+
4
+ def self.create_main_repo
5
+ FileUtils.mkdir_p tmp_path
6
+ Dir.chdir(tmp_path) do
7
+ FileUtils.mkdir "main_repo"
8
+ Dir.chdir('main_repo') do
9
+ `git init`
10
+ `echo 'first content' > starter_repo`
11
+ `git add starter_repo`
12
+ `git commit -m "starter repo"`
13
+ end
14
+ end
15
+ end
16
+
17
+ def self.tmp_path
18
+ "/tmp/giternal_test"
19
+ end
20
+
21
+ def self.giternal_base
22
+ @@giternal_base
23
+ end
24
+
25
+ def self.base_project_dir
26
+ tmp_path + '/main_repo'
27
+ end
28
+
29
+ def self.run(*args)
30
+ `#{giternal_base}/bin/giternal #{args.join(' ')}`
31
+ end
32
+
33
+ def self.create_repo(repo_name)
34
+ Dir.chdir(tmp_path) do
35
+ FileUtils.mkdir_p "externals/#{repo_name}"
36
+ `cd externals/#{repo_name} && git init`
37
+ end
38
+ add_content repo_name
39
+ add_to_config_file repo_name
40
+ end
41
+
42
+ def self.add_to_config_file(repo_name)
43
+ config_dir = tmp_path + '/main_repo/config'
44
+ FileUtils.mkdir(config_dir) unless File.directory?(config_dir)
45
+ Dir.chdir(config_dir) do
46
+ `echo #{repo_name}: >> giternal.yml`
47
+ `echo ' repo: #{external_path(repo_name)}' >> giternal.yml`
48
+ `echo ' path: dependencies' >> giternal.yml`
49
+ end
50
+ end
51
+
52
+ def self.add_content(repo_name, content=repo_name)
53
+ Dir.chdir(tmp_path + "/externals/#{repo_name}") do
54
+ `echo #{content} >> #{content} && git add #{content}`
55
+ `git commit #{content} -m "added content to #{content}"`
56
+ end
57
+ end
58
+
59
+ def self.external_path(repo_name)
60
+ File.expand_path(tmp_path + "/externals/#{repo_name}")
61
+ end
62
+
63
+ def self.checked_out_path(repo_name)
64
+ File.expand_path(tmp_path + "/main_repo/dependencies/#{repo_name}")
65
+ end
66
+
67
+ def self.clean!
68
+ FileUtils.rm_rf tmp_path
69
+ %w(GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE).each {|var| ENV[var] = nil }
70
+ end
71
+
72
+ def self.update_externals(*args)
73
+ Dir.chdir(tmp_path + '/main_repo') do
74
+ GiternalHelper.run('update', *args)
75
+ end
76
+ end
77
+
78
+ def self.freeze_externals(*args)
79
+ Dir.chdir(tmp_path + '/main_repo') do
80
+ GiternalHelper.run("freeze", *args)
81
+ end
82
+ end
83
+
84
+ def self.unfreeze_externals(*args)
85
+ Dir.chdir(tmp_path + '/main_repo') do
86
+ GiternalHelper.run("unfreeze", *args)
87
+ end
88
+ end
89
+
90
+ def self.repo_contents(path)
91
+ Dir.chdir(path) do
92
+ contents = `git cat-file -p HEAD`
93
+ unless contents.include?('tree') && contents.include?('author')
94
+ raise "something is wrong with the repo, output doesn't contain expected git elements:\n\n #{contents}"
95
+ end
96
+ contents
97
+ end
98
+ end
99
+
100
+ def self.add_external_to_ignore(repo_name)
101
+ Dir.chdir(tmp_path + '/main_repo') do
102
+ `echo 'dependencies/#{repo_name}' >> .gitignore`
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,10 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module Giternal
5
+
6
+ end
7
+
8
+ require 'giternal/repository'
9
+ require 'giternal/yaml_config'
10
+ require 'giternal/app'
@@ -0,0 +1,69 @@
1
+ module Giternal
2
+ class App
3
+ def initialize(base_dir)
4
+ @base_dir = base_dir
5
+ end
6
+
7
+ def update(*dirs)
8
+ if dirs.empty?
9
+ config.each_repo {|r| r.update }
10
+ else
11
+ dirs.each do |dir|
12
+ if repo = config.find_repo(dir)
13
+ repo.update
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ def freezify(*dirs)
20
+ if dirs.empty?
21
+ config.each_repo {|r| r.freezify }
22
+ else
23
+ dirs.each do |dir|
24
+ if repo = config.find_repo(dir)
25
+ repo.freezify
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def unfreezify(*dirs)
32
+ if dirs.empty?
33
+ config.each_repo {|r| r.unfreezify }
34
+ else
35
+ dirs.each do |dir|
36
+ if repo = config.find_repo(dir)
37
+ repo.unfreezify
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def run(action, *args)
44
+ case action
45
+ when "freeze"
46
+ freezify(*args)
47
+ when "unfreeze"
48
+ unfreezify(*args)
49
+ else
50
+ send(action, *args)
51
+ end
52
+ end
53
+
54
+ def config
55
+ return @config if @config
56
+
57
+ config_file = ['config/giternal.yml', '.giternal.yml'].detect do |file|
58
+ File.file? File.expand_path(@base_dir + '/' + file)
59
+ end
60
+
61
+ if config_file.nil?
62
+ $stderr.puts "config/giternal.yml is missing"
63
+ exit 1
64
+ end
65
+
66
+ @config = YamlConfig.new(@base_dir, File.read(config_file))
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,109 @@
1
+ require 'fileutils'
2
+
3
+ module Giternal
4
+ class Repository
5
+ class << self
6
+ attr_accessor :verbose
7
+ end
8
+ attr_accessor :verbose
9
+
10
+ def initialize(base_dir, name, repo_url, rel_path, branch=nil)
11
+ @base_dir = base_dir
12
+ @name = name
13
+ @repo_url = repo_url
14
+ @rel_path = rel_path
15
+ if branch != nil
16
+ @branch = branch
17
+ else
18
+ @branch = "master"
19
+ end
20
+ @verbose = self.class.verbose
21
+ end
22
+
23
+ def update
24
+ git_ignore_self
25
+
26
+ return true if frozen?
27
+ FileUtils.mkdir_p checkout_path unless File.exist?(checkout_path)
28
+ if checked_out?
29
+ if !File.exist?(repo_path + '/.git')
30
+ raise "Directory '#{@name}' exists but is not a git repository"
31
+ else
32
+ current_branch = (`cd #{repo_path} && git branch`).split[1]
33
+ if current_branch != @branch
34
+ `cd #{repo_path} && git checkout #{@branch}`
35
+ end
36
+ update_output { `cd #{repo_path} && git pull 2>&1` }
37
+ end
38
+ else
39
+ update_output { `cd #{checkout_path} && git clone #{@repo_url} #{@name} -b #{@branch}` }
40
+ end
41
+ true
42
+ end
43
+
44
+ def freezify
45
+ return true if frozen? || !checked_out?
46
+
47
+ Dir.chdir(repo_path) do
48
+ `find .git | sort | xargs tar czf .git.frozen.tgz`
49
+ FileUtils.rm_r('.git')
50
+ end
51
+ `cd #{@base_dir} && git add -f #{rel_repo_path}`
52
+ true
53
+ end
54
+
55
+ def unfreezify
56
+ return true unless frozen?
57
+
58
+ Dir.chdir(repo_path) do
59
+ `tar xzf .git.frozen.tgz`
60
+ FileUtils.rm('.git.frozen.tgz')
61
+ end
62
+ `cd #{@base_dir} && git rm -r --cached #{rel_repo_path}`
63
+ true
64
+ end
65
+
66
+ def frozen?
67
+ File.exist?(repo_path + '/.git.frozen.tgz')
68
+ end
69
+
70
+ def checked_out?
71
+ File.exist?(repo_path)
72
+ end
73
+
74
+ private
75
+ def checkout_path
76
+ File.expand_path(File.join(@base_dir, @rel_path))
77
+ end
78
+
79
+ def repo_path
80
+ File.expand_path(checkout_path + '/' + @name)
81
+ end
82
+
83
+ def rel_repo_path
84
+ @rel_path + '/' + @name
85
+ end
86
+
87
+ def update_output(&block)
88
+ puts "Updating #{@name}" if verbose
89
+ block.call
90
+ puts " ..updated\n" if verbose
91
+ end
92
+
93
+ def git_ignore_self
94
+ Dir.chdir(@base_dir) do
95
+ contents = File.read('.gitignore') if File.exist?('.gitignore')
96
+
97
+ unless contents.to_s.include?(rel_repo_path)
98
+ File.open('.gitignore', 'w') do |file|
99
+ if contents
100
+ file << contents
101
+ file << "\n" unless contents[-1] == 10 # ascii code for \n
102
+ end
103
+ file << rel_repo_path << "\n"
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,9 @@
1
+ module Giternal
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 2
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ require 'yaml'
2
+
3
+ module Giternal
4
+ class YamlConfig
5
+ def initialize(base_dir, yaml_string)
6
+ @base_dir = base_dir
7
+ @config_hash = YAML.load yaml_string
8
+ end
9
+
10
+ def each_repo
11
+ repositories.each { |r| yield(r) if block_given? }
12
+ end
13
+
14
+ def find_repo(path)
15
+ @config_hash.each do |name, attributes|
16
+ if path == File.join(attributes["path"], name)
17
+ return Repository.new(@base_dir, name, attributes["repo"], attributes["path"])
18
+ end
19
+ end
20
+ return nil
21
+ end
22
+
23
+ private
24
+ def repositories
25
+ @config_hash.map do |name, attributes|
26
+ Repository.new(@base_dir, name, attributes["repo"], attributes["path"], attributes["branch"])
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,64 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+
3
+ module Giternal
4
+ describe App do
5
+ before(:each) do
6
+ @app = App.new("some_fake_dir")
7
+ @mock_config = stub("config", :null_object => true)
8
+ end
9
+
10
+ describe "loading the config file" do
11
+ before(:each) do
12
+ File.stub!(:file?).and_return true
13
+ File.stub!(:read).and_return "yaml config"
14
+ YamlConfig.stub!(:new).and_return @mock_config
15
+ end
16
+
17
+ it "should look for config/giternal.yml" do
18
+ File.should_receive(:file?).with(/some_fake_dir\/config\/giternal\.yml/)
19
+ @app.config
20
+ end
21
+
22
+ it "should look for .giternal.yml if giternal.yml does not exist" do
23
+ File.should_receive(:file?).with(/some_fake_dir\/config\/giternal\.yml/).and_return false
24
+ File.should_receive(:file?).with(/some_fake_dir\/\.giternal\.yml/).and_return true
25
+ @app.config
26
+ end
27
+
28
+ it "should exit with an error when no config file exists" do
29
+ File.stub!(:file?).and_return false
30
+ $stderr.should_receive(:puts)
31
+ @app.should_receive(:exit).with(1)
32
+ @app.config
33
+ end
34
+
35
+ it "should create a config from the config file" do
36
+ YamlConfig.should_receive(:new).with('some_fake_dir', "yaml config").and_return @mock_config
37
+ @app.config
38
+ end
39
+ end
40
+
41
+ describe "app actions" do
42
+ before(:each) do
43
+ @app.stub!(:config).and_return @mock_config
44
+ @mock_repo = mock("repo")
45
+ @mock_config.stub!(:each_repo).and_yield(@mock_repo)
46
+ end
47
+
48
+ it "should update each of the repositories" do
49
+ @mock_repo.should_receive(:update)
50
+ @app.update
51
+ end
52
+
53
+ it "should freeze each of the repositories" do
54
+ @mock_repo.should_receive(:freezify)
55
+ @app.freezify
56
+ end
57
+
58
+ it "should unfreeze each of the repositories" do
59
+ @mock_repo.should_receive(:unfreezify)
60
+ @app.unfreezify
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,149 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+
3
+ module Giternal
4
+ describe Repository do
5
+ before(:each) do
6
+ GiternalHelper.create_main_repo
7
+ GiternalHelper.create_repo 'foo'
8
+ @repository = Repository.new(GiternalHelper.base_project_dir, "foo",
9
+ GiternalHelper.external_path('foo'),
10
+ 'dependencies')
11
+ end
12
+
13
+ it "should check itself out to a dir" do
14
+ @repository.update
15
+ File.file?(GiternalHelper.checked_out_path('foo/foo')).should be_true
16
+ File.read(GiternalHelper.checked_out_path('foo/foo')).strip.
17
+ should == 'foo'
18
+ end
19
+
20
+ it "should be ignored from git" do
21
+ @repository.update
22
+ Dir.chdir(GiternalHelper.base_project_dir) do
23
+ # TODO: What I really want is to say it shouldn't include 'foo'
24
+ `git status`.should_not include('dependencies')
25
+ File.read('.gitignore').should == "dependencies/foo\n"
26
+ end
27
+ end
28
+
29
+ it "should only add itself to .gitignore if it's not already there" do
30
+ Dir.chdir(GiternalHelper.base_project_dir) do
31
+ File.open('.gitignore', 'w') {|f| f << "dependencies/foo\n" }
32
+ end
33
+
34
+ @repository.update
35
+
36
+ Dir.chdir(GiternalHelper.base_project_dir) do
37
+ File.read('.gitignore').should == "dependencies/foo\n"
38
+ end
39
+ end
40
+
41
+ it "adds a newline if it needs to" do
42
+ Dir.chdir(GiternalHelper.base_project_dir) do
43
+ File.open('.gitignore', 'w') {|f| f << "something/else" }
44
+ end
45
+
46
+ @repository.update
47
+
48
+ Dir.chdir(GiternalHelper.base_project_dir) do
49
+ File.read('.gitignore').should == "something/else\ndependencies/foo\n"
50
+ end
51
+ end
52
+
53
+ it "should not show any output when verbose mode is off" do
54
+ @repository.verbose = false
55
+ @repository.should_not_receive(:puts)
56
+ @repository.update
57
+ end
58
+
59
+ it "should not show output when verbose mode is on" do
60
+ @repository.verbose = true
61
+ @repository.should_receive(:puts).any_number_of_times
62
+ @repository.update
63
+ end
64
+
65
+ it "should update the repo when it's already been checked out" do
66
+ @repository.update
67
+ GiternalHelper.add_content 'foo', 'newfile'
68
+ @repository.update
69
+ File.file?(GiternalHelper.checked_out_path('foo/newfile')).should be_true
70
+ File.read(GiternalHelper.checked_out_path('foo/newfile')).strip.
71
+ should == 'newfile'
72
+ end
73
+
74
+ it "should raise an error if the directory exists but there's no .git dir" do
75
+ FileUtils.mkdir_p(GiternalHelper.checked_out_path('foo'))
76
+ lambda {
77
+ @repository.update
78
+ }.should raise_error(/Directory 'foo' exists but is not a git repository/)
79
+ end
80
+
81
+ describe "freezify" do
82
+ before(:each) do
83
+ GiternalHelper.create_repo('external')
84
+ @repository = Repository.new(GiternalHelper.base_project_dir, 'external',
85
+ GiternalHelper.external_path('external'),
86
+ 'dependencies')
87
+ @repository.update
88
+ end
89
+
90
+ it "should archive the .git dir" do
91
+ @repository.freezify
92
+ File.file?(GiternalHelper.checked_out_path('external/.git.frozen.tgz')).should be_true
93
+ end
94
+
95
+ it "should get rid of the .git dir" do
96
+ File.directory?(GiternalHelper.checked_out_path('external/.git')).should be_true
97
+ @repository.freezify
98
+ File.directory?(GiternalHelper.checked_out_path('external/.git')).should be_false
99
+ end
100
+ end
101
+
102
+ it "should simply return if updated when frozen" do
103
+ @repository.update
104
+ @repository.freezify
105
+ lambda { @repository.update }.should_not raise_error
106
+ end
107
+
108
+ it "should simply return when made to freeze when already frozen" do
109
+ @repository.update
110
+ @repository.freezify
111
+ lambda { @repository.freezify }.should_not raise_error
112
+ end
113
+
114
+ it "should simply return when made to freeze before checked out" do
115
+ lambda { @repository.freezify }.should_not raise_error
116
+ end
117
+
118
+ it "should simply return when made to unfreeze before checked out" do
119
+ lambda { @repository.unfreezify }.should_not raise_error
120
+ end
121
+
122
+ it "should simply return when made to unfreeze when already unfrozen" do
123
+ @repository.update
124
+ lambda { @repository.unfreezify }.should_not raise_error
125
+ end
126
+
127
+ describe "unfreezify" do
128
+ before(:each) do
129
+ GiternalHelper.create_repo('main')
130
+ GiternalHelper.create_repo('external')
131
+ @repository = Repository.new(GiternalHelper.base_project_dir, 'external',
132
+ GiternalHelper.external_path('external'),
133
+ 'dependencies')
134
+ @repository.update
135
+ @repository.freezify
136
+ end
137
+
138
+ it "should unarchive the .git dir" do
139
+ @repository.unfreezify
140
+ File.directory?(GiternalHelper.checked_out_path('external/.git')).should be_true
141
+ end
142
+
143
+ it "should remove the archived file" do
144
+ @repository.unfreezify
145
+ File.file?(GiternalHelper.checked_out_path('external/.git.frozen.tgz')).should be_false
146
+ end
147
+ end
148
+ end
149
+ end