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 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
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ *pkg
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
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
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: []