omnirepo 0.5.0.0.pre
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.
- 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: []
|