git-si 0.3.1 → 0.4.0

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,153 @@
1
+ require "git/si/errors"
2
+
3
+ module Git
4
+
5
+ module Si
6
+
7
+ module Actions
8
+
9
+ def do_status_action( args=[] )
10
+ on_local_branch do
11
+ return if do_revisions_differ()
12
+ svn_status = get_command_output( Git::Si::SvnControl.status_command( args ) )
13
+ print_colordiff Git::Si::SvnControl.parse_svn_status( svn_status ).join( "\n" )
14
+ end
15
+ end
16
+
17
+ def do_diff_action( args=[] )
18
+ on_local_branch do
19
+ return if do_revisions_differ()
20
+
21
+ notice_message "Adding any files that are not already in svn to ensure an accurate diff."
22
+ do_readd_action
23
+
24
+ print_colordiff get_command_output( Git::Si::SvnControl.diff_command( args ) )
25
+ end
26
+ end
27
+
28
+ def do_add_action( args=[] )
29
+ on_local_branch do
30
+ run_command( Git::Si::SvnControl.add_command( args ) )
31
+ run_command( Git::Si::GitControl.add_command( args ) )
32
+ end
33
+ end
34
+
35
+ def do_readd_action
36
+ on_local_branch do
37
+ files_to_add = []
38
+ Git::Si::SvnControl.parse_unknown_files( get_command_output( Git::Si::SvnControl.status_command ) ).each do |filename|
39
+ if is_file_in_git?( filename )
40
+ files_to_add << filename if filename != '.gitignore'
41
+ end
42
+ end
43
+
44
+ if files_to_add.empty?
45
+ notice_message "There are no files to add."
46
+ return
47
+ end
48
+
49
+ using_stderr do
50
+ files_to_add.each do |filename|
51
+ say filename
52
+ end
53
+ if yes? "Do you want to add the above files to svn? [y/N] ", :green
54
+ run_command( Git::Si::SvnControl.add_command( files_to_add ) )
55
+ success_message "Added files to svn that had been added to git."
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+
62
+ def do_fetch_action
63
+ stashed_changes = stash_local_changes
64
+ on_mirror_branch do
65
+ notice_message "Fetching remote data from svn"
66
+ updated_files = get_command_output( Git::Si::SvnControl.update_command )
67
+ revert_files_to_svn_update( updated_files )
68
+ delete_files_after_svn_update( updated_files )
69
+ add_files_after_svn_update( updated_files )
70
+ run_command( Git::Si::GitControl.commit_revision_command( get_svn_revision ) )
71
+ end
72
+ unstash_local_changes( stashed_changes )
73
+ success_message "fetch complete!"
74
+ end
75
+
76
+ def do_rebase_action
77
+ on_local_branch do
78
+ stashed_changes = stash_local_changes
79
+ run_command( Git::Si::GitControl.rebase_command( get_mirror_branch ) )
80
+ unstash_local_changes( stashed_changes )
81
+ success_message "rebase complete!"
82
+ end
83
+ end
84
+
85
+ def do_pull_action
86
+ do_fetch_action
87
+ do_rebase_action
88
+ end
89
+
90
+ def do_commit_action
91
+ local_branch = get_local_branch()
92
+ if local_branch == 'master'
93
+ error_message "Please do not commit changes on the master branch"
94
+ return
95
+ end
96
+
97
+ on_local_branch do
98
+ raise Git::Si::GitError.new("There are local changes; please commit them before continuing.") if are_there_git_changes?
99
+
100
+ notice_message "Adding any files that are not already in svn to ensure changes are committed."
101
+ do_readd_action
102
+
103
+ svn_diff = get_command_output( Git::Si::SvnControl.diff_command )
104
+ raise Git::Si::SvnError.new("There are no changes to commit.") if svn_diff.strip.empty?
105
+
106
+ run_command( Git::Si::SvnControl.commit_command )
107
+ success_message "commit complete!"
108
+
109
+ if are_there_git_changes? and yes?( "Some files were added or modified during the commit; should I revert them? [y/N] ", :yellow )
110
+ run_command( Git::Si::GitControl.hard_reset_command )
111
+ end
112
+ end
113
+
114
+ notice_message "Updating mirror branch to latest commit"
115
+ do_fetch_action
116
+
117
+ delete_committed_branch( local_branch ) if yes?( "Do you want to switch to the master branch and delete the committed branch '#{local_branch}'? [y/N] ", :green )
118
+ end
119
+
120
+ def do_init_action
121
+ on_local_branch do
122
+ # check for svn repo
123
+ run_command( Git::Si::SvnControl.info_command, { :allow_errors => true } )
124
+ raise Git::Si::SvnError.new("No svn repository was found here. Maybe you're in the wrong directory?") unless did_last_command_succeed?
125
+
126
+ # make sure svn repo is up-to-date
127
+ run_command( Git::Si::SvnControl.update_command )
128
+
129
+ make_a_commit = false
130
+
131
+ # check for existing .git repo
132
+ make_a_commit = true if create_git_repository()
133
+
134
+ # check for existing .gitignore
135
+ make_a_commit = true if create_gitignore()
136
+
137
+ # make initial commit
138
+ if make_a_commit
139
+ notice_message "Making initial commit."
140
+ run_command( Git::Si::GitControl.commit_revision_command(get_svn_revision) )
141
+ end
142
+
143
+ # check for exiting mirror branch
144
+ create_mirror_branch()
145
+
146
+ success_message "init complete!"
147
+ end
148
+ end
149
+
150
+ end
151
+ end
152
+ end
153
+
@@ -0,0 +1,20 @@
1
+ module Git
2
+ module Si
3
+
4
+ class GitSiError < StandardError
5
+ end
6
+
7
+ class ShellError < GitSiError
8
+ end
9
+
10
+ class GitError < GitSiError
11
+ end
12
+
13
+ class SvnError < GitSiError
14
+ end
15
+
16
+ class VersionError < GitSiError
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,112 @@
1
+ require "git/si/version"
2
+
3
+ module Git
4
+ module Si
5
+ class GitControl
6
+ @@default_git_binary = 'git'
7
+ @@git_binary = 'git'
8
+
9
+ def self.git_binary=(binary)
10
+ @@git_binary = binary && binary.length > 0 ? binary : @@default_git_binary
11
+ end
12
+
13
+ def self.status_command(*args)
14
+ command = "#{@@git_binary} status --porcelain"
15
+ if ( args.length > 0 )
16
+ command += " " + args.join(' ')
17
+ end
18
+ command
19
+ end
20
+
21
+ def self.log_command(*args)
22
+ command = "#{@@git_binary} log"
23
+ if ( args.length > 0 )
24
+ command += " " + args.join(' ')
25
+ end
26
+ command
27
+ end
28
+
29
+ def self.parse_last_svn_revision(info)
30
+ results = info.match(/svn update to version (\d+)/i)
31
+ return results[1] if results
32
+ end
33
+
34
+ def self.add_command(*files)
35
+ raise GitSiError.new("Add command requires filenames") if ( files.length == 0 )
36
+ "#{@@git_binary} add " + files.join(' ')
37
+ end
38
+
39
+ def self.are_there_changes?(status_output)
40
+ status_output.match(/^\s*[MADRC]/)
41
+ end
42
+
43
+ def self.commit_revision_command(revision)
44
+ version = Git::Si::Version.version
45
+ "#{@@git_binary} commit --allow-empty -am 'git-si #{version} svn update to version #{revision}'"
46
+ end
47
+
48
+ def self.stash_command
49
+ "#{@@git_binary} stash"
50
+ end
51
+
52
+ def self.unstash_command
53
+ "#{@@git_binary} stash pop"
54
+ end
55
+
56
+ def self.rebase_command(branch)
57
+ raise GitSiError.new("Rebase command requires branch name") if branch.empty?
58
+ "#{@@git_binary} rebase '#{branch}'"
59
+ end
60
+
61
+ def self.checkout_command(branch)
62
+ raise GitSiError.new("Checkout command requires branch name") if branch.empty?
63
+ "#{@@git_binary} checkout #{branch}"
64
+ end
65
+
66
+ def self.create_branch_command(branch)
67
+ raise GitSiError.new("New branch command requires branch name") if branch.empty?
68
+ "#{@@git_binary} branch #{branch}"
69
+ end
70
+
71
+ def self.delete_branch_command(branch)
72
+ raise GitSiError.new("Delete branch command requires branch name") if branch.empty?
73
+ "#{@@git_binary} branch -D #{branch}"
74
+ end
75
+
76
+ def self.branch_command
77
+ "#{@@git_binary} branch"
78
+ end
79
+
80
+ def self.parse_current_branch(git_branches)
81
+ results = git_branches.match(/^\*\s+(\S+)/)
82
+ return results[1] if results
83
+ end
84
+
85
+ def self.hard_reset_command
86
+ "#{@@git_binary} reset --hard HEAD"
87
+ end
88
+
89
+ def self.list_file_command(filename)
90
+ raise GitSiError.new("List file command requires filename") if filename.empty?
91
+ "#{@@git_binary} ls-files #{filename}"
92
+ end
93
+
94
+ def self.init_command
95
+ "#{@@git_binary} init"
96
+ end
97
+
98
+ def self.show_branch_command(branch)
99
+ raise GitSiError.new("Show branch command requires branch name") if branch.empty?
100
+ "#{@@git_binary} show-ref refs/heads/#{branch}"
101
+ end
102
+
103
+ def self.delete_command(filename)
104
+ raise GitSiError.new("Remove file command requires filename") if filename.empty?
105
+ "#{@@git_binary} rm #{filename}"
106
+ end
107
+
108
+ end
109
+ end
110
+ end
111
+
112
+
@@ -0,0 +1,23 @@
1
+ module Git
2
+ module Si
3
+ class GitIgnore
4
+ @@gitignore_patterns = [".*", "!.gitignore", ".svn", "*.sw?", ".config", "*.err", "*.pid", "*.log", "svn-commit.*", "*.orig", "node_modules"]
5
+
6
+ def self.ignore_patterns
7
+ @@gitignore_patterns
8
+ end
9
+
10
+ def self.get_missing_lines_from(lines, patterns=@@gitignore_patterns)
11
+ patterns.reject do |pattern|
12
+ lines.detect do |line|
13
+ line.strip.eql? pattern.strip
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+
22
+
23
+
@@ -0,0 +1,135 @@
1
+ module Git
2
+ module Si
3
+ class SvnControl
4
+ @@default_svn_binary = 'svn'
5
+ @@svn_binary = 'svn'
6
+
7
+ def self.svn_binary=(binary)
8
+ @@svn_binary = binary && binary.length > 0 ? binary : @@default_svn_binary
9
+ end
10
+
11
+ def self.status_command(*args)
12
+ command = "#{@@svn_binary} status --ignore-externals"
13
+ if ( args.length > 0 )
14
+ command += " " + args.join(' ')
15
+ end
16
+ command
17
+ end
18
+
19
+ def self.info_command
20
+ "#{@@svn_binary} info"
21
+ end
22
+
23
+ def self.diff_command(*args)
24
+ command = "#{@@svn_binary} diff"
25
+ if ( args.length > 0 )
26
+ command += " " + args.join(' ')
27
+ end
28
+ command
29
+ end
30
+
31
+ def self.parse_last_revision(svn_info)
32
+ results = svn_info.match(/^Revision:\s+(\d+)/)
33
+ return results[1] if results
34
+ return nil
35
+ end
36
+
37
+ def self.parse_root_path(svn_info)
38
+ results = svn_info.match(/Root Path:\s+(.+)/)
39
+ return results[1] if results
40
+ return nil
41
+ end
42
+
43
+ def self.parse_updated_files(svn_update_output)
44
+ svn_update_output.split(/\r?\n/).collect do |line|
45
+ line.strip.match(Regexp.union(/^\s*[AGU]\s+(\S.+)/, /^Restored '(.+)'/, /^Resolved conflicted state of '(.+)'/)) do |pattern|
46
+ pattern.to_a.compact.last
47
+ end
48
+ end.compact
49
+ end
50
+
51
+ def self.parse_deleted_files(svn_update_output)
52
+ svn_update_output.split(/\r?\n/).collect do |line|
53
+ line.strip.match(Regexp.union(/^\s*D\s+(\S.+)/)) do |pattern|
54
+ pattern.to_a.compact.last
55
+ end
56
+ end.compact
57
+ end
58
+
59
+ def self.parse_conflicted_files(svn_update_output)
60
+ svn_update_output.split(/\r?\n/).collect do |line|
61
+ line.strip.match(Regexp.union(/^\s*C\s+(\S.+)/, /^Resolved conflicted state of '(.+)'/)) do |pattern|
62
+ pattern.to_a.compact.last
63
+ end
64
+ end.compact
65
+ end
66
+
67
+ def self.parse_unknown_files(svn_update_output)
68
+ svn_update_output.split(/\r?\n/).collect do |line|
69
+ line.strip.match(/^\s*\?\s+(\S.+)/) do |pattern|
70
+ pattern.to_a.compact.last
71
+ end
72
+ end.compact
73
+ end
74
+
75
+ def self.add_command(*files)
76
+ raise GitSiError.new("Add command requires filenames") if ( files.length == 0 )
77
+ "#{@@svn_binary} add " + files.join(' ')
78
+ end
79
+
80
+ def self.blame_command(*files)
81
+ raise GitSiError.new("Blame command requires filenames") if ( files.length == 0 )
82
+ "#{@@svn_binary} blame " + files.join(' ')
83
+ end
84
+
85
+ def self.update_command
86
+ "#{@@svn_binary} up --accept theirs-full --ignore-externals"
87
+ end
88
+
89
+ def self.revert_command(*args)
90
+ command = "#{@@svn_binary} revert -R"
91
+ if ( args.length > 0 )
92
+ command += " " + args.join(' ')
93
+ else
94
+ command += " ."
95
+ end
96
+ command
97
+ end
98
+
99
+ def self.commit_command(*args)
100
+ command = "#{@@svn_binary} commit"
101
+ if ( args.length > 0 )
102
+ command += " " + args.join(' ')
103
+ end
104
+ command
105
+ end
106
+
107
+ def self.list_file_command
108
+ "#{@@svn_binary} list -R"
109
+ end
110
+
111
+ def self.parse_file_list(list_output)
112
+ list_output.split(/\r?\n/).collect do |filename|
113
+ filename.strip if filename.strip !~ Regexp.union( /\/$/, /^\./, /\/\./ ) and not filename.empty?
114
+ end.compact
115
+ end
116
+
117
+ def self.parse_svn_status(status_string)
118
+ return '' unless status_string
119
+ status_string.split(/\r?\n/).select do |line|
120
+ line.strip !~ /(^X|\.git|\.swp$)/
121
+ end
122
+ end
123
+
124
+ def self.parse_external_repos(status_string)
125
+ status_string.split(/\r?\n/).collect do |line|
126
+ line.strip.match(/^\s*X\s+(\S.+)/) do |pattern|
127
+ pattern.to_a.compact.last
128
+ end
129
+ end.compact
130
+ end
131
+
132
+ end
133
+ end
134
+ end
135
+