omnirepo 0.5.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/CHANGES.md +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +20 -0
- data/README.md +90 -0
- data/Rakefile +1 -0
- data/bin/omnirepo +253 -0
- data/omnirepo.gemspec +18 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0de193035ffbc63293ac558163fa9bc6519e0597
|
4
|
+
data.tar.gz: 5597b8bfa5d0ac31564a58fc2444884ed1c24ff3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 98f40124f15c5be9e75017e11446788d1cc1882f396b228218065b1412e3ee57defdac1efb33f5ddd476707729ed923852d6a9fc11a90e4d5ab6d9188b050912
|
7
|
+
data.tar.gz: ebb92830746b0dbd4dceae34bcd51ef6a57abfcc637be28b349e2371a20f2eb7c66ecfdef4f1a84d3c9de731ad9dd3dafc61d016fa678be5d1ca8e2e634e28fc
|
data/.gitignore
ADDED
data/CHANGES.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
HEAD
|
2
|
+
-----
|
3
|
+
* Initial release, put together for [celluloid/core](https://github.com/celluloid/core).
|
4
|
+
* Added `.omnirepo` configuration file support. YAML file with these options:
|
5
|
+
* [required, if using .omnirepo] `repositories` array, of individual repositories.
|
6
|
+
* [optional] `submodules` if `remove` will remove submodules from repositories.
|
7
|
+
* [optional] `merging` can be `skip` and it will just prepare but not merge.
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011-2014 Donovan Keme
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# omnirepo
|
2
|
+
|
3
|
+
Create a new omnibus repository out of a collection of existing GitHub repositories.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation:
|
7
|
+
|
8
|
+
```
|
9
|
+
gem install omnirepo
|
10
|
+
```
|
11
|
+
|
12
|
+
## What exactly does it do with repositories?!
|
13
|
+
|
14
|
+
0. Checks for the destination omnibus directory.
|
15
|
+
0. Clones source repositories into a temporary directory.
|
16
|
+
0. It uses mirroring, to pull in all branches and tags.
|
17
|
+
0. It immediately removes any remote `origin` detected.
|
18
|
+
0. Preserves the git history for each repository.
|
19
|
+
0. (optional) If desired, it removes any submodules present first.
|
20
|
+
0. It also renames all branches and tags to be `<repository>/<name>`.
|
21
|
+
0. Does garbage collection on the repository being migrated.
|
22
|
+
0. Imports each source repository as a sub-directory of the omnibus repository.
|
23
|
+
0. Does garbage collection on the new omnibus repository.
|
24
|
+
0. **Does not push the new omnibus repository live.**
|
25
|
+
|
26
|
+
### System Requirements:
|
27
|
+
|
28
|
+
* Unix-based operating system, with `ruby` and `git` preinstalled.
|
29
|
+
* Prefers `tmpfs` partition located at `/dev/shm` for temporary storage.
|
30
|
+
* Read access to all remote repositories involed.
|
31
|
+
|
32
|
+
### Usage:
|
33
|
+
|
34
|
+
```sh
|
35
|
+
omnirepo <username/organization> <destination-omnibus> <source-repository> [...]
|
36
|
+
```
|
37
|
+
|
38
|
+
### Example:
|
39
|
+
|
40
|
+
If these self-contained repositories on GitHub need to be merged together into one repository:
|
41
|
+
|
42
|
+
* `org9/repoA`
|
43
|
+
* `org9/repoB`
|
44
|
+
* `org9/repoC`
|
45
|
+
|
46
|
+
And the directory housing the future location of the omnibus repository on GitHub is:
|
47
|
+
|
48
|
+
* `org9/repo0`
|
49
|
+
|
50
|
+
This would be your command:
|
51
|
+
|
52
|
+
```sh
|
53
|
+
omnirepo org9 repo0 repoA repoB repoC
|
54
|
+
```
|
55
|
+
# Use with a configuration file:
|
56
|
+
|
57
|
+
For the scenario above, you can create a configuration file as follows:
|
58
|
+
|
59
|
+
```yml
|
60
|
+
repositories:
|
61
|
+
- repoA
|
62
|
+
- repoB
|
63
|
+
- repoC
|
64
|
+
```
|
65
|
+
|
66
|
+
Save that file as `repo0/.omnirepo`
|
67
|
+
|
68
|
+
Then you can run this command:
|
69
|
+
|
70
|
+
```sh
|
71
|
+
omnirepo org9 repo0
|
72
|
+
```
|
73
|
+
|
74
|
+
|
75
|
+
## Future Features
|
76
|
+
|
77
|
+
- [x] Read repositories from a configuration file.
|
78
|
+
- [ ] Bring together source repositories from multiple possible organizations.
|
79
|
+
- [ ] ...missing something? [Request it](https://github.com/digitalextremist/omnirepo/issues/new)...
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
* Fork this repository on GitHub.
|
84
|
+
* Make your changes and send a pull request.
|
85
|
+
|
86
|
+
## License
|
87
|
+
|
88
|
+
Copyright (c) 2015 Donovan Keme.
|
89
|
+
|
90
|
+
Distributed under the MIT License. See [LICENSE.txt](https://github.com/digitalextremist/omnirepo/LICENSE.txt) for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/omnirepo
ADDED
@@ -0,0 +1,253 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
start = Time.now #de Not monotonic, but bah.
|
4
|
+
puts "Omnibus repository unification tool..."
|
5
|
+
|
6
|
+
def omnirepo?
|
7
|
+
if File.exists?(File.join("#{Dir.pwd}/#{ARGV[1]}", ".omnirepo"))
|
8
|
+
require 'psych'
|
9
|
+
return true
|
10
|
+
end
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
def urandom_id
|
15
|
+
`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`
|
16
|
+
end
|
17
|
+
|
18
|
+
def success?(results)
|
19
|
+
return false unless results.is_a?(Array)
|
20
|
+
results.uniq!
|
21
|
+
return false unless results.one?
|
22
|
+
results.first == true
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
|
27
|
+
#de TODO: Validate owner.
|
28
|
+
#de TODO: Allow use of literal paths, vs. relative.
|
29
|
+
#de TODO: Check permissions/writeability, etc.
|
30
|
+
|
31
|
+
if ARGV.length == 2 && omnirepo?
|
32
|
+
OWNER = ARGV.shift
|
33
|
+
OMNIBUS = "#{Dir.pwd}/#{ARGV.shift}"
|
34
|
+
CONFIG = Psych.load_file(File.join(OMNIBUS, ".omnirepo"))
|
35
|
+
unless CONFIG.is_a?(Hash) && CONFIG["repositories"].is_a?(Array)
|
36
|
+
puts "Onmirepo configuration file invalid."
|
37
|
+
exit!
|
38
|
+
end
|
39
|
+
REPOSITORIES = CONFIG['repositories'].uniq
|
40
|
+
GIT = CONFIG["git"] if CONFIG["git"].is_a?(String)
|
41
|
+
elsif ARGV.length <= 3
|
42
|
+
puts "Usage: omnirepo <owner org/user> <destination-omnibus-dir> <source-repo1> <source-repo2> [...]"
|
43
|
+
puts "No owner organization/username supplied." unless ARGV.any?
|
44
|
+
puts "No destination omnibus directory supplied." unless ARGV.length >= 2
|
45
|
+
puts "No source repositories supplied." unless ARGV.length == 3
|
46
|
+
puts "Only one source repository supplied." if ARGV.length == 3
|
47
|
+
exit!
|
48
|
+
else
|
49
|
+
OWNER = ARGV.shift
|
50
|
+
OMNIBUS = "#{Dir.pwd}/#{ARGV.shift}"
|
51
|
+
REPOSITORIES = ARGV.uniq
|
52
|
+
CONFIG = {}
|
53
|
+
end
|
54
|
+
|
55
|
+
GIT = "git@github.com".freeze unless defined? GIT
|
56
|
+
|
57
|
+
tmp='/dev/shm'
|
58
|
+
tmp='/tmp' unless Dir.exists?(tmp)
|
59
|
+
TMP="#{tmp}/omnirepo.#{urandom_id}".chomp.strip
|
60
|
+
|
61
|
+
unless Dir.mkdir(TMP)
|
62
|
+
STDERR.puts "ERROR: Unable to make the temporary working directory: #{TMP}"
|
63
|
+
exit!
|
64
|
+
end
|
65
|
+
|
66
|
+
puts LINE = "-----------------------------------------------------------------------------------".freeze
|
67
|
+
|
68
|
+
unless Dir.exists?(OMNIBUS)
|
69
|
+
puts "Destination omnibus directory does not exist: #{OMNIBUS}"
|
70
|
+
exit!
|
71
|
+
end
|
72
|
+
|
73
|
+
puts "Owner organization/user: #{OWNER}"
|
74
|
+
puts "Destination omnibus: #{OMNIBUS}"
|
75
|
+
puts "Working directory: #{TMP}"
|
76
|
+
puts LINE
|
77
|
+
|
78
|
+
Dir.chdir(OMNIBUS)
|
79
|
+
|
80
|
+
if `git show 2> /dev/null | grep "commit" | wc -l`.to_i != 1
|
81
|
+
puts LINE
|
82
|
+
STDERR.puts "ERROR: Destination omnibus directory is not a git repository, or not ready."
|
83
|
+
exit!
|
84
|
+
end
|
85
|
+
|
86
|
+
#de TODO: Further validate omnibus repository.
|
87
|
+
|
88
|
+
failures = []
|
89
|
+
|
90
|
+
REPOSITORIES.each { |repo|
|
91
|
+
|
92
|
+
puts "\n\n\n#{LINE}"
|
93
|
+
puts "Adding the #{repo} repository..."
|
94
|
+
puts "Source: #{GIT}:#{OWNER}/#{repo}.git"
|
95
|
+
puts LINE
|
96
|
+
|
97
|
+
unless Dir.chdir(TMP)
|
98
|
+
STDERR.puts "ERROR: Failure to change to the temporary working directory."
|
99
|
+
exit!
|
100
|
+
end
|
101
|
+
|
102
|
+
unless system("git clone --mirror '#{GIT}:#{OWNER}/#{repo}.git' #{repo}")
|
103
|
+
puts "FERROR: ailed to clone: #{repo}"
|
104
|
+
exit!
|
105
|
+
end
|
106
|
+
|
107
|
+
unless Dir.chdir(repo_bare = File.join(TMP, repo))
|
108
|
+
STDERR.puts "ERROR: Failed to mirror the #{repo} repository."
|
109
|
+
exit!
|
110
|
+
end
|
111
|
+
|
112
|
+
if `git remote | grep origin | wc -l`.to_i > 0
|
113
|
+
`git remote rm origin > /dev/null 2> /dev/null`
|
114
|
+
end
|
115
|
+
|
116
|
+
branches = []
|
117
|
+
`git branch | grep -v master | grep -v "refs/"`.split("\n").each { |branch|
|
118
|
+
begin
|
119
|
+
result = nil
|
120
|
+
branches << (branch = branch.strip.chomp)
|
121
|
+
result = system("git branch -m '#{branch}' '#{repo}/#{branch}")
|
122
|
+
rescue => ex
|
123
|
+
STDERR.puts "WARN: Could not migrate the #{branch} branch.\nReason: #{ex}"
|
124
|
+
ensure
|
125
|
+
failures << "#{repo} / branch: #{branch}" unless result == true
|
126
|
+
end
|
127
|
+
}
|
128
|
+
|
129
|
+
repo_clone = "../#{repo}.clone"
|
130
|
+
unless cloned = system("git clone . #{repo_clone} > /dev/null")
|
131
|
+
STDERR.puts "ERROR: Failed to make local clone of #{repo}."
|
132
|
+
failures << "#{repo} / locally clone"
|
133
|
+
next
|
134
|
+
end
|
135
|
+
|
136
|
+
Dir.chdir(repo_clone)
|
137
|
+
|
138
|
+
begin
|
139
|
+
if CONFIG['submodules'] == 'remove'
|
140
|
+
if File.exists?(module_config = File.join(repo_bare, repo_clone, ".gitmodules"))
|
141
|
+
submodules = File.read(module_config)
|
142
|
+
.split("\n")
|
143
|
+
.map { |line|
|
144
|
+
if line.include?("path =")
|
145
|
+
submodule = line.sub("path =", "").chomp.strip
|
146
|
+
unless submodule.empty?
|
147
|
+
`git rm -rf ./#{submodule}`
|
148
|
+
submodule
|
149
|
+
end
|
150
|
+
else
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
}.compact
|
154
|
+
result = []
|
155
|
+
result << system("git rm -rf .gitmodules")
|
156
|
+
result << system("git commit -am '[omnirepo] removing submodules: #{submodules.join(', ')}'")
|
157
|
+
result << system("git push")
|
158
|
+
failures << "#{repo} / submodules: remove .gitmodules, then commit/push" unless success?(result)
|
159
|
+
puts "#{LINE}\nRemoved submodules first: #{submodules.join(', ')}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
rescue => ex
|
163
|
+
STDERR.puts "WARN: Could not remove associated submodules.\nReason: #{ex}"
|
164
|
+
failures << "#{repo} / remove submodules"
|
165
|
+
ensure
|
166
|
+
Dir.chdir(repo_bare)
|
167
|
+
end
|
168
|
+
|
169
|
+
puts "#{LINE}\nPreserving change history and files, but making the repository a sub-directory..."
|
170
|
+
print "... please wait: "
|
171
|
+
|
172
|
+
unless system("git filter-branch --tree-filter " +
|
173
|
+
"'mkdir #{repo}; " +
|
174
|
+
"find -maxdepth 1 " +
|
175
|
+
"-not -name . " +
|
176
|
+
"-not -name .git " +
|
177
|
+
"-not -name #{repo} " +
|
178
|
+
"| xargs -I{} mv {} #{repo}' " +
|
179
|
+
"-d #{TMP}/#{urandom_id} -- --all")
|
180
|
+
failures << "#{repo} / repository tree-filter"
|
181
|
+
end
|
182
|
+
|
183
|
+
unless system("git commit -am '[omnirepo] merging the rearranged file structure'")
|
184
|
+
failures << "#{repo} / merge rearranged file structure"
|
185
|
+
STDERR.puts "ERROR: Could not merge-in rearranged file structure."
|
186
|
+
next
|
187
|
+
end
|
188
|
+
|
189
|
+
tags = []
|
190
|
+
`git tag`.split("\n").each { |tag|
|
191
|
+
begin
|
192
|
+
result = []
|
193
|
+
tags << (tag = tag.chomp.strip)
|
194
|
+
result << system("git tag '#{repo}/#{tag}' '#{tag}' > /dev/null")
|
195
|
+
result << system("git tag -d '#{tag}' > /dev/null")
|
196
|
+
rescue => ex
|
197
|
+
STDERR.puts "WARN: Could not migrate the #{tag} tag.\nReason: #{ex}"
|
198
|
+
result << false
|
199
|
+
ensure
|
200
|
+
failures << "#{repo} / tag: #{tag}" unless success?(result)
|
201
|
+
end
|
202
|
+
}
|
203
|
+
|
204
|
+
puts "#{LINE}\nGarbage collection of source repository...\n#{LINE}"
|
205
|
+
failures << "#{repo} / garbage collection" unless `git gc --aggressive`
|
206
|
+
|
207
|
+
if CONFIG['merging'] == 'skip'
|
208
|
+
puts "Skipping actual merge into omnibus..."
|
209
|
+
next
|
210
|
+
end
|
211
|
+
|
212
|
+
puts "#{LINE}\nMerging the prepared repository into the omnibus...\n#{LINE}"
|
213
|
+
|
214
|
+
result = []
|
215
|
+
Dir.chdir(OMNIBUS)
|
216
|
+
result << system("git remote add #{repo} #{repo_bare}")
|
217
|
+
result << system("git fetch #{repo}")
|
218
|
+
result << system("git merge --no-ff #{repo}/master --commit '[omnirepo] merging in the #{repo} repository.'")
|
219
|
+
result << system("git remote rm #{repo}")
|
220
|
+
|
221
|
+
unless success?(result)
|
222
|
+
failures << "#{repo} / merge into omnibus"
|
223
|
+
next
|
224
|
+
end
|
225
|
+
|
226
|
+
if branches.any?
|
227
|
+
puts "#{LINE}\nThese branches were migrated:\n#{LINE}"
|
228
|
+
branches.each { |branch| puts "#{branch.rjust(35)} is now #{repo}/#{branch}\n" }
|
229
|
+
end
|
230
|
+
|
231
|
+
if tags.any?
|
232
|
+
puts "#{LINE}\nThese tags were migrated:\n#{LINE}"
|
233
|
+
tags.each { |tag| puts "#{tag.rjust(35)} is now #{repo}/#{tag}\n" }
|
234
|
+
end
|
235
|
+
|
236
|
+
}
|
237
|
+
|
238
|
+
puts "\n\n\n"
|
239
|
+
#de TODO: Delete working directory, or at least give config or command line option to do so.
|
240
|
+
puts "#{LINE}\nThere were the following failures:\n#{LINE}\n#{failures.join("\n")}" if failures.any?
|
241
|
+
puts "\n\n\n#{LINE}"
|
242
|
+
puts "Omnibus unification of repositories finished in #{"%0.4f" % (Time.now.to_f - start.to_f)} seconds."
|
243
|
+
puts "#{LINE}\nRemove your temporary working directory when you are ready:"
|
244
|
+
puts " #{TMP}"
|
245
|
+
puts "#{LINE}\nWARNING: Be sure to check over the new omnibus repository before pushing it!"
|
246
|
+
puts " Each repository has been committed into it."
|
247
|
+
puts LINE
|
248
|
+
|
249
|
+
rescue => ex
|
250
|
+
puts "Exiting prematurely. Re-run to make an intact omnibus repository."
|
251
|
+
STDERR.puts "Error: #{ex}" unless ex.is_a?(Interrupt)
|
252
|
+
exit(false)
|
253
|
+
end
|
data/omnirepo.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.authors = ["Donovan Keme"]
|
5
|
+
gem.email = ["code@extremist.digital"]
|
6
|
+
gem.description = "Create a new omnibus repository out of collections of existing GitHub repositories."
|
7
|
+
gem.summary = "Unify GitHub repositories as one repository containing them all as sub-directories."
|
8
|
+
gem.homepage = "https://github.com/digitalextremist/omnirepo"
|
9
|
+
|
10
|
+
gem.files = `git ls-files`.split($\)
|
11
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
12
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
|
+
gem.name = "omnirepo"
|
14
|
+
gem.version = '0.5.0.0.pre'
|
15
|
+
gem.licenses = ['MIT']
|
16
|
+
gem.required_ruby_version = ">= 1.9.2"
|
17
|
+
gem.required_rubygems_version = ">= 1.3.6"
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omnirepo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0.0.pre
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Donovan Keme
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-08 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Create a new omnibus repository out of collections of existing GitHub
|
14
|
+
repositories.
|
15
|
+
email:
|
16
|
+
- code@extremist.digital
|
17
|
+
executables:
|
18
|
+
- omnirepo
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- ".gitignore"
|
23
|
+
- CHANGES.md
|
24
|
+
- Gemfile
|
25
|
+
- LICENSE.txt
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- bin/omnirepo
|
29
|
+
- omnirepo.gemspec
|
30
|
+
homepage: https://github.com/digitalextremist/omnirepo
|
31
|
+
licenses:
|
32
|
+
- MIT
|
33
|
+
metadata: {}
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.9.2
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.3.6
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 2.4.8
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: Unify GitHub repositories as one repository containing them all as sub-directories.
|
54
|
+
test_files: []
|