├── .gitignore ├── LICENSE.md ├── README.md ├── Sublime Text ├── .gitignore ├── autogit.py └── site-packages │ └── dulwich │ ├── __init__.py │ ├── _compat.py │ ├── client.py │ ├── config.py │ ├── diff_tree.py │ ├── errors.py │ ├── fastexport.py │ ├── file.py │ ├── hooks.py │ ├── index.py │ ├── log_utils.py │ ├── lru_cache.py │ ├── object_store.py │ ├── objects.py │ ├── pack.py │ ├── patch.py │ ├── protocol.py │ ├── repo.py │ ├── server.py │ ├── tests │ ├── __init__.py │ ├── test_blackbox.py │ ├── test_client.py │ ├── test_config.py │ ├── test_diff_tree.py │ ├── test_fastexport.py │ ├── test_file.py │ ├── test_hooks.py │ ├── test_index.py │ ├── test_lru_cache.py │ ├── test_missing_obj_finder.py │ ├── test_object_store.py │ ├── test_objects.py │ ├── test_pack.py │ ├── test_patch.py │ ├── test_protocol.py │ ├── test_repository.py │ ├── test_server.py │ ├── test_utils.py │ ├── test_walk.py │ ├── test_web.py │ └── utils.py │ ├── walk.py │ └── web.py └── Visual Studio ├── Backup └── autogit.sln ├── Ganji.Repo ├── Ganji.Repo.csproj ├── GitProvider.cs ├── GitProviderLibGit2Sharp.cs ├── Key.snk ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── autogit.sln ├── autogit ├── GlobalSuppressions.cs ├── Guids.cs ├── Key.snk ├── License.rtf ├── PkgCmdID.cs ├── Properties │ └── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Resources │ ├── Images.png │ └── Package.ico ├── SaveListener.cs ├── VSPackage.resx ├── autogit.csproj ├── autogit.vsct ├── autogitPackage.cs └── source.extension.vsixmanifest └── packages ├── LibGit2Sharp.0.13.0.0 ├── App_Readme │ ├── LibGit2Sharp.CHANGES.md │ ├── LibGit2Sharp.LICENSE.md │ ├── LibGit2Sharp.README.md │ └── libgit2.license.txt ├── LibGit2Sharp.0.13.0.0.nupkg ├── LibGit2Sharp.0.13.0.0.nuspec ├── NativeBinaries │ ├── amd64 │ │ └── git2-7940036.dll │ └── x86 │ │ └── git2-7940036.dll ├── Tools │ ├── GetLibGit2SharpPostBuildCmd.ps1 │ ├── install.ps1 │ └── uninstall.ps1 └── lib │ └── net35 │ ├── LibGit2Sharp.dll │ ├── LibGit2Sharp.dll.unsigned │ ├── LibGit2Sharp.il │ ├── LibGit2Sharp.libgit2_hash.txt │ ├── LibGit2Sharp.libgit2sharp_hash.txt │ ├── LibGit2Sharp.res │ ├── LibGit2Sharp.xml │ └── keyPair.snk └── repositories.config /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Chris Parnin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | autogit 2 | ======= 3 | 4 | Automatic git checkins from your text editor saves. 5 | 6 | `autogit` will automatically commit a version of a file to a local git repository everytime a change is saved in a text or code editor. 7 | 8 | ### Why use autogit? 9 | 10 | Some simple reasons: 11 | 12 | * simple insurance against accidental changes or deletions. 13 | * makes it easier to support smarter undo, backtracking, or exploratory programming. 14 | * resume a task or track a task by seeing changes at a fine-grain level as they happened. 15 | * light-weight, stays invisible until you need it. 16 | 17 | Some deeper reasons: 18 | 19 | * **Better Task Resumption:** research suggests that resuming an interrupted task or reviewing a change made by another is made easier when changes can be reviewed in an time-ordered manner (in comparision to a flat commit). 20 | 21 | * **Auto-blog:** [automark](https://github.com/chrisparnin/automark) is a sister project that can examine a git repository and then automatically generate a markdown file, in a format suitable for publishing a blog post. 22 | 23 | * **Personal Analytics:** Watts Humphrey has advocated the idea of tracking personal activity for self-improvement, using methods such as the Personal Software Process. Using services, such as [codealike](http://codealike.com/) or [codeivate](http://www.codeivate.com/), you can track things like time spent editing, etc. Tracking the *actual* changes can take this analysis to another level. 24 | 25 | * **Api Analytics:** Frequent mistakes are made when programming or using particular apis. This can be analyzed: "You spent 3 hours figuring out how to correctly use pygit2.create_commit(), create github issue?" 26 | 27 | 28 | ### Supported Editors 29 | 30 | autogit is available as a set of plugins for the following editors: 31 | 32 | * Visual Studio 33 | 34 | * Sublime Text 2 35 | 36 | Future editor support is planned. [Pull requests](https://github.com/chrisparnin/autogit/pulls) or suggestions in [issues](https://github.com/chrisparnin/autogit/issues/new) are welcome! 37 | 38 | ### Installing autogit 39 | 40 | autogit is at an *experimental* stage. 41 | 42 | #### Visual Studio 43 | 44 | You can install autogit from the Visual Studio gallery: 45 | http://visualstudiogallery.msdn.microsoft.com/45a3d62b-955e-43cb-9d91-255a837d5f35 46 | 47 | #### Sublime Text 2 48 | 49 | You can install autogit from the Package Control site: 50 | https://sublime.wbond.net/packages/autogit 51 | -------------------------------------------------------------------------------- /Sublime Text/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /Sublime Text/autogit.py: -------------------------------------------------------------------------------- 1 | import sublime, sublime_plugin, os, codecs 2 | import shutil 3 | import sys, platform 4 | from os.path import expanduser 5 | 6 | # Paths 7 | 8 | HOME = expanduser("~") 9 | #PYGIT2_BASEDIR = '/Library/Python/2.7/site-packages/' 10 | PACKAGE_PATH = os.path.dirname(os.path.realpath(__file__)) 11 | 12 | PYGIT2_BASEDIR = os.path.join(PACKAGE_PATH,'site-packages') 13 | 14 | AUTOGIT_PATH = '/usr/local/autogit/' 15 | 16 | # libgit2_path = os.getenv("LIBGIT2") 17 | #if libgit2_path is None: 18 | # if os.name == 'nt': 19 | # program_files = os.getenv("ProgramFiles") 20 | # libgit2_path = '%s\libgit2' % program_files 21 | # else: 22 | # libgit2_path = '/usr/local' 23 | 24 | # What version are we running? 25 | 26 | WinOsVersion,_,_,_ = platform.win32_ver() 27 | MacOsVersion,_,_ = platform.mac_ver() 28 | if( WinOsVersion ): 29 | APPDIR = os.getenv("APPDATA") 30 | AUTOGIT_PATH = "%s/autogit/" % APPDIR 31 | AUTOGIT_PATH = AUTOGIT_PATH.replace("\\","/") 32 | 33 | 34 | elif( MacOsVersion ): 35 | AUTOGIT_PATH = "%s/Library/Application Support/autogit/" % HOME 36 | 37 | if( not os.path.isdir( AUTOGIT_PATH ) ): 38 | os.makedirs(AUTOGIT_PATH) 39 | 40 | print WinOsVersion, MacOsVersion, AUTOGIT_PATH 41 | 42 | # Because sublime uses its own python env, set pygit path manually before loading module: 43 | def fixPath(): 44 | for path in sys.path: 45 | if path == PYGIT2_BASEDIR: 46 | return 47 | sys.path.append(PYGIT2_BASEDIR) 48 | fixPath(); 49 | 50 | print sys.path 51 | 52 | #import pygit2 53 | from dulwich.repo import Repo 54 | from dulwich.index import index_entry_from_stat, changes_from_tree 55 | from dulwich.objects import Blob 56 | from dulwich.diff_tree import tree_changes 57 | 58 | class ExampleCommand(sublime_plugin.TextCommand): 59 | def run(self, edit): 60 | self.view.insert(edit, 0, "Hello, World!") 61 | 62 | class GitRepository(): 63 | def init(self,path): 64 | #pygit2.init_repository(path, False) 65 | if( not os.path.isdir( path ) ): 66 | os.makedirs(path) 67 | Repo.init(path) 68 | 69 | def adjustPath(self, gitRoot, filePath): 70 | drive, path = os.path.splitdrive(filePath) 71 | if drive: 72 | path = path.replace("\\","/") 73 | if( path.startswith("/") ): 74 | path = path[1:] 75 | joined = os.path.join( gitRoot, path ) 76 | joined = joined.replace("\\","/") 77 | return joined 78 | 79 | def dulwichCommit(self, filePath, fullPath, kind): 80 | 81 | git = Repo(AUTOGIT_PATH) 82 | staged = map(str,[filePath]) 83 | git.stage( staged ) 84 | 85 | index = git.open_index() 86 | 87 | try: 88 | committer = git._get_user_identity() 89 | except ValueError: 90 | committer = "autogit" 91 | 92 | try: 93 | head = git.head() 94 | except KeyError: 95 | return git.do_commit( '%s - autogit commit (via dulwich)' % kind, committer=committer) 96 | 97 | changes = list(tree_changes(git, index.commit(git.object_store), git['HEAD'].tree)) 98 | if changes and len(changes) > 0: 99 | return git.do_commit( '%s - autogit commit (via dulwich)' % kind, committer=committer) 100 | return None 101 | 102 | def pygit2Commit(self, filePath, kind): 103 | 104 | git = pygit2.Repository(GIT_REPOSITORY_PATH) 105 | 106 | index = git.index 107 | index.read() 108 | index.add(filePath) 109 | #oid = index[filePath] 110 | index.write(); 111 | 112 | for entry in index: 113 | print "added %s %s to index" % (entry.path, entry.hex) 114 | 115 | status = git.status() 116 | try: 117 | status[filePath] 118 | except KeyError: 119 | # If there is nothing different since last save, git status will report no difference. 120 | return 121 | 122 | try: 123 | HEAD = git.revparse_single('HEAD') 124 | parents = [HEAD.hex] 125 | except KeyError: 126 | parents = [] 127 | 128 | commit = git.create_commit( 129 | 'HEAD', 130 | pygit2.Signature('autogit you', 'autogit@ninlabs.com'), 131 | pygit2.Signature('autogit you', 'autogit@ninlabs.com'), 132 | '%s - autogit commit' % kind, 133 | index.write_tree(), 134 | parents 135 | ) 136 | 137 | return commit 138 | 139 | class AutoGitEvent(sublime_plugin.EventListener): 140 | 141 | # this will normally not result in a commit unless it was a first time saving file or file was externally modified. 142 | def on_pre_save(self, view): 143 | 144 | #body = view.substr(sublime.Region(0, view.size())).encode('utf-8') 145 | #with open(path,'w') as f: 146 | # f.write( body ) 147 | # f.close() 148 | 149 | commit = self.handleCommit(view, "pre save") 150 | if commit: 151 | print "*******", view.file_name(), "pre save - commited" 152 | 153 | def on_post_save(self, view): 154 | #with codecs.open(view.file_name(), "r", "utf-8") as f: 155 | # print f.read() 156 | commit = self.handleCommit(view, "post save") 157 | if commit: 158 | print "*******", view.file_name(), "postsave - commited" 159 | 160 | def handleCommit(self,view, kind): 161 | repo = GitRepository() 162 | path = repo.adjustPath( AUTOGIT_PATH, view.file_name() ) 163 | 164 | dir = os.path.dirname( path ) 165 | 166 | if( not os.path.isdir(dir) ): 167 | os.makedirs(dir) 168 | 169 | shutil.copy2(view.file_name(),path) 170 | 171 | ## rel path is needed for commit 172 | relPath = path.replace(AUTOGIT_PATH, "") 173 | if( relPath.startswith("/") ): 174 | relPath = relPath[1:] 175 | 176 | 177 | #return repo.commit(relPath, kind) 178 | return repo.dulwichCommit(relPath, path, kind) 179 | 180 | ### Create initial autogit repository if it doesn't exist 181 | 182 | GIT_REPOSITORY_PATH = os.path.join( AUTOGIT_PATH, ".git" ) 183 | if( not os.path.isdir( GIT_REPOSITORY_PATH ) ): 184 | repo = GitRepository() 185 | repo.init(AUTOGIT_PATH) 186 | print "##### created git repo: " + GIT_REPOSITORY_PATH 187 | 188 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/__init__.py: -------------------------------------------------------------------------------- 1 | # __init__.py -- The git module of dulwich 2 | # Copyright (C) 2007 James Westby 3 | # Copyright (C) 2008 Jelmer Vernooij 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; version 2 8 | # of the License or (at your option) any later version of 9 | # the License. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | # MA 02110-1301, USA. 20 | 21 | 22 | """Python implementation of the Git file formats and protocols.""" 23 | 24 | __version__ = (0, 9, 1) 25 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/errors.py: -------------------------------------------------------------------------------- 1 | # errors.py -- errors for dulwich 2 | # Copyright (C) 2007 James Westby 3 | # Copyright (C) 2009 Jelmer Vernooij 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; version 2 8 | # or (at your option) any later version of the License. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | # MA 02110-1301, USA. 19 | 20 | """Dulwich-related exception classes and utility functions.""" 21 | 22 | import binascii 23 | 24 | 25 | class ChecksumMismatch(Exception): 26 | """A checksum didn't match the expected contents.""" 27 | 28 | def __init__(self, expected, got, extra=None): 29 | if len(expected) == 20: 30 | expected = binascii.hexlify(expected) 31 | if len(got) == 20: 32 | got = binascii.hexlify(got) 33 | self.expected = expected 34 | self.got = got 35 | self.extra = extra 36 | if self.extra is None: 37 | Exception.__init__(self, 38 | "Checksum mismatch: Expected %s, got %s" % (expected, got)) 39 | else: 40 | Exception.__init__(self, 41 | "Checksum mismatch: Expected %s, got %s; %s" % 42 | (expected, got, extra)) 43 | 44 | 45 | class WrongObjectException(Exception): 46 | """Baseclass for all the _ is not a _ exceptions on objects. 47 | 48 | Do not instantiate directly. 49 | 50 | Subclasses should define a type_name attribute that indicates what 51 | was expected if they were raised. 52 | """ 53 | 54 | def __init__(self, sha, *args, **kwargs): 55 | Exception.__init__(self, "%s is not a %s" % (sha, self.type_name)) 56 | 57 | 58 | class NotCommitError(WrongObjectException): 59 | """Indicates that the sha requested does not point to a commit.""" 60 | 61 | type_name = 'commit' 62 | 63 | 64 | class NotTreeError(WrongObjectException): 65 | """Indicates that the sha requested does not point to a tree.""" 66 | 67 | type_name = 'tree' 68 | 69 | 70 | class NotTagError(WrongObjectException): 71 | """Indicates that the sha requested does not point to a tag.""" 72 | 73 | type_name = 'tag' 74 | 75 | 76 | class NotBlobError(WrongObjectException): 77 | """Indicates that the sha requested does not point to a blob.""" 78 | 79 | type_name = 'blob' 80 | 81 | 82 | class MissingCommitError(Exception): 83 | """Indicates that a commit was not found in the repository""" 84 | 85 | def __init__(self, sha, *args, **kwargs): 86 | self.sha = sha 87 | Exception.__init__(self, "%s is not in the revision store" % sha) 88 | 89 | 90 | class ObjectMissing(Exception): 91 | """Indicates that a requested object is missing.""" 92 | 93 | def __init__(self, sha, *args, **kwargs): 94 | Exception.__init__(self, "%s is not in the pack" % sha) 95 | 96 | 97 | class ApplyDeltaError(Exception): 98 | """Indicates that applying a delta failed.""" 99 | 100 | def __init__(self, *args, **kwargs): 101 | Exception.__init__(self, *args, **kwargs) 102 | 103 | 104 | class NotGitRepository(Exception): 105 | """Indicates that no Git repository was found.""" 106 | 107 | def __init__(self, *args, **kwargs): 108 | Exception.__init__(self, *args, **kwargs) 109 | 110 | 111 | class GitProtocolError(Exception): 112 | """Git protocol exception.""" 113 | 114 | def __init__(self, *args, **kwargs): 115 | Exception.__init__(self, *args, **kwargs) 116 | 117 | 118 | class SendPackError(GitProtocolError): 119 | """An error occurred during send_pack.""" 120 | 121 | def __init__(self, *args, **kwargs): 122 | Exception.__init__(self, *args, **kwargs) 123 | 124 | 125 | class UpdateRefsError(GitProtocolError): 126 | """The server reported errors updating refs.""" 127 | 128 | def __init__(self, *args, **kwargs): 129 | self.ref_status = kwargs.pop('ref_status') 130 | Exception.__init__(self, *args, **kwargs) 131 | 132 | 133 | class HangupException(GitProtocolError): 134 | """Hangup exception.""" 135 | 136 | def __init__(self): 137 | Exception.__init__(self, 138 | "The remote server unexpectedly closed the connection.") 139 | 140 | 141 | class UnexpectedCommandError(GitProtocolError): 142 | """Unexpected command received in a proto line.""" 143 | 144 | def __init__(self, command): 145 | if command is None: 146 | command = 'flush-pkt' 147 | else: 148 | command = 'command %s' % command 149 | GitProtocolError.__init__(self, 'Protocol got unexpected %s' % command) 150 | 151 | 152 | class FileFormatException(Exception): 153 | """Base class for exceptions relating to reading git file formats.""" 154 | 155 | 156 | class PackedRefsException(FileFormatException): 157 | """Indicates an error parsing a packed-refs file.""" 158 | 159 | 160 | class ObjectFormatException(FileFormatException): 161 | """Indicates an error parsing an object.""" 162 | 163 | 164 | class NoIndexPresent(Exception): 165 | """No index is present.""" 166 | 167 | 168 | class CommitError(Exception): 169 | """An error occurred while performing a commit.""" 170 | 171 | 172 | class RefFormatError(Exception): 173 | """Indicates an invalid ref name.""" 174 | 175 | 176 | class HookError(Exception): 177 | """An error occurred while executing a hook.""" 178 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/fastexport.py: -------------------------------------------------------------------------------- 1 | # __init__.py -- Fast export/import functionality 2 | # Copyright (C) 2010 Jelmer Vernooij 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # of the License or (at your option) any later version of 8 | # the License. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | # MA 02110-1301, USA. 19 | 20 | 21 | """Fast export/import functionality.""" 22 | 23 | from dulwich.index import ( 24 | commit_tree, 25 | ) 26 | from dulwich.objects import ( 27 | Blob, 28 | Commit, 29 | Tag, 30 | ) 31 | from fastimport import ( 32 | commands, 33 | errors as fastimport_errors, 34 | parser, 35 | processor, 36 | ) 37 | 38 | import stat 39 | 40 | 41 | def split_email(text): 42 | (name, email) = text.rsplit(" <", 1) 43 | return (name, email.rstrip(">")) 44 | 45 | 46 | class GitFastExporter(object): 47 | """Generate a fast-export output stream for Git objects.""" 48 | 49 | def __init__(self, outf, store): 50 | self.outf = outf 51 | self.store = store 52 | self.markers = {} 53 | self._marker_idx = 0 54 | 55 | def print_cmd(self, cmd): 56 | self.outf.write("%r\n" % cmd) 57 | 58 | def _allocate_marker(self): 59 | self._marker_idx+=1 60 | return str(self._marker_idx) 61 | 62 | def _export_blob(self, blob): 63 | marker = self._allocate_marker() 64 | self.markers[marker] = blob.id 65 | return (commands.BlobCommand(marker, blob.data), marker) 66 | 67 | def emit_blob(self, blob): 68 | (cmd, marker) = self._export_blob(blob) 69 | self.print_cmd(cmd) 70 | return marker 71 | 72 | def _iter_files(self, base_tree, new_tree): 73 | for (old_path, new_path), (old_mode, new_mode), (old_hexsha, new_hexsha) in \ 74 | self.store.tree_changes(base_tree, new_tree): 75 | if new_path is None: 76 | yield commands.FileDeleteCommand(old_path) 77 | continue 78 | if not stat.S_ISDIR(new_mode): 79 | blob = self.store[new_hexsha] 80 | marker = self.emit_blob(blob) 81 | if old_path != new_path and old_path is not None: 82 | yield commands.FileRenameCommand(old_path, new_path) 83 | if old_mode != new_mode or old_hexsha != new_hexsha: 84 | yield commands.FileModifyCommand(new_path, new_mode, marker, None) 85 | 86 | def _export_commit(self, commit, ref, base_tree=None): 87 | file_cmds = list(self._iter_files(base_tree, commit.tree)) 88 | marker = self._allocate_marker() 89 | if commit.parents: 90 | from_ = commit.parents[0] 91 | merges = commit.parents[1:] 92 | else: 93 | from_ = None 94 | merges = [] 95 | author, author_email = split_email(commit.author) 96 | committer, committer_email = split_email(commit.committer) 97 | cmd = commands.CommitCommand(ref, marker, 98 | (author, author_email, commit.author_time, commit.author_timezone), 99 | (committer, committer_email, commit.commit_time, commit.commit_timezone), 100 | commit.message, from_, merges, file_cmds) 101 | return (cmd, marker) 102 | 103 | def emit_commit(self, commit, ref, base_tree=None): 104 | cmd, marker = self._export_commit(commit, ref, base_tree) 105 | self.print_cmd(cmd) 106 | return marker 107 | 108 | 109 | class GitImportProcessor(processor.ImportProcessor): 110 | """An import processor that imports into a Git repository using Dulwich. 111 | 112 | """ 113 | # FIXME: Batch creation of objects? 114 | 115 | def __init__(self, repo, params=None, verbose=False, outf=None): 116 | processor.ImportProcessor.__init__(self, params, verbose) 117 | self.repo = repo 118 | self.last_commit = None 119 | self.markers = {} 120 | self._contents = {} 121 | 122 | def import_stream(self, stream): 123 | p = parser.ImportParser(stream) 124 | self.process(p.iter_commands) 125 | return self.markers 126 | 127 | def blob_handler(self, cmd): 128 | """Process a BlobCommand.""" 129 | blob = Blob.from_string(cmd.data) 130 | self.repo.object_store.add_object(blob) 131 | if cmd.mark: 132 | self.markers[cmd.mark] = blob.id 133 | 134 | def checkpoint_handler(self, cmd): 135 | """Process a CheckpointCommand.""" 136 | pass 137 | 138 | def commit_handler(self, cmd): 139 | """Process a CommitCommand.""" 140 | commit = Commit() 141 | if cmd.author is not None: 142 | author = cmd.author 143 | else: 144 | author = cmd.committer 145 | (author_name, author_email, author_timestamp, author_timezone) = author 146 | (committer_name, committer_email, commit_timestamp, commit_timezone) = cmd.committer 147 | commit.author = "%s <%s>" % (author_name, author_email) 148 | commit.author_timezone = author_timezone 149 | commit.author_time = int(author_timestamp) 150 | commit.committer = "%s <%s>" % (committer_name, committer_email) 151 | commit.commit_timezone = commit_timezone 152 | commit.commit_time = int(commit_timestamp) 153 | commit.message = cmd.message 154 | commit.parents = [] 155 | if cmd.from_: 156 | self._reset_base(cmd.from_) 157 | for filecmd in cmd.iter_files(): 158 | if filecmd.name == "filemodify": 159 | if filecmd.data is not None: 160 | blob = Blob.from_string(filecmd.data) 161 | self.repo.object_store.add(blob) 162 | blob_id = blob.id 163 | else: 164 | assert filecmd.dataref[0] == ":", "non-marker refs not supported yet" 165 | blob_id = self.markers[filecmd.dataref[1:]] 166 | self._contents[filecmd.path] = (filecmd.mode, blob_id) 167 | elif filecmd.name == "filedelete": 168 | del self._contents[filecmd.path] 169 | elif filecmd.name == "filecopy": 170 | self._contents[filecmd.dest_path] = self._contents[filecmd.src_path] 171 | elif filecmd.name == "filerename": 172 | self._contents[filecmd.new_path] = self._contents[filecmd.old_path] 173 | del self._contents[filecmd.old_path] 174 | elif filecmd.name == "filedeleteall": 175 | self._contents = {} 176 | else: 177 | raise Exception("Command %s not supported" % filecmd.name) 178 | commit.tree = commit_tree(self.repo.object_store, 179 | ((path, hexsha, mode) for (path, (mode, hexsha)) in 180 | self._contents.iteritems())) 181 | if self.last_commit is not None: 182 | commit.parents.append(self.last_commit) 183 | commit.parents += cmd.merges 184 | self.repo.object_store.add_object(commit) 185 | self.repo[cmd.ref] = commit.id 186 | self.last_commit = commit.id 187 | if cmd.mark: 188 | self.markers[cmd.mark] = commit.id 189 | 190 | def progress_handler(self, cmd): 191 | """Process a ProgressCommand.""" 192 | pass 193 | 194 | def _reset_base(self, commit_id): 195 | if self.last_commit == commit_id: 196 | return 197 | self.last_commit = commit_id 198 | self._contents = {} 199 | tree_id = self.repo[commit_id].tree 200 | for (path, mode, hexsha) in ( 201 | self.repo.object_store.iter_tree_contents(tree_id)): 202 | self._contents[path] = (mode, hexsha) 203 | 204 | def reset_handler(self, cmd): 205 | """Process a ResetCommand.""" 206 | self._reset_base(cmd.from_) 207 | self.rep.refs[cmd.from_] = cmd.id 208 | 209 | def tag_handler(self, cmd): 210 | """Process a TagCommand.""" 211 | tag = Tag() 212 | tag.tagger = cmd.tagger 213 | tag.message = cmd.message 214 | tag.name = cmd.tag 215 | self.repo.add_object(tag) 216 | self.repo.refs["refs/tags/" + tag.name] = tag.id 217 | 218 | def feature_handler(self, cmd): 219 | """Process a FeatureCommand.""" 220 | raise fastimport_errors.UnknownFeature(cmd.feature_name) 221 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/file.py: -------------------------------------------------------------------------------- 1 | # file.py -- Safe access to git files 2 | # Copyright (C) 2010 Google, Inc. 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # of the License or (at your option) a later version of the License. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | # MA 02110-1301, USA. 18 | 19 | """Safe access to git files.""" 20 | 21 | import errno 22 | import os 23 | import tempfile 24 | 25 | def ensure_dir_exists(dirname): 26 | """Ensure a directory exists, creating if necessary.""" 27 | try: 28 | os.makedirs(dirname) 29 | except OSError, e: 30 | if e.errno != errno.EEXIST: 31 | raise 32 | 33 | 34 | def fancy_rename(oldname, newname): 35 | """Rename file with temporary backup file to rollback if rename fails""" 36 | if not os.path.exists(newname): 37 | try: 38 | os.rename(oldname, newname) 39 | except OSError, e: 40 | raise 41 | return 42 | 43 | # destination file exists 44 | try: 45 | (fd, tmpfile) = tempfile.mkstemp(".tmp", prefix=oldname+".", dir=".") 46 | os.close(fd) 47 | os.remove(tmpfile) 48 | except OSError, e: 49 | # either file could not be created (e.g. permission problem) 50 | # or could not be deleted (e.g. rude virus scanner) 51 | raise 52 | try: 53 | os.rename(newname, tmpfile) 54 | except OSError, e: 55 | raise # no rename occurred 56 | try: 57 | os.rename(oldname, newname) 58 | except OSError, e: 59 | os.rename(tmpfile, newname) 60 | raise 61 | os.remove(tmpfile) 62 | 63 | 64 | def GitFile(filename, mode='rb', bufsize=-1): 65 | """Create a file object that obeys the git file locking protocol. 66 | 67 | :return: a builtin file object or a _GitFile object 68 | 69 | :note: See _GitFile for a description of the file locking protocol. 70 | 71 | Only read-only and write-only (binary) modes are supported; r+, w+, and a 72 | are not. To read and write from the same file, you can take advantage of 73 | the fact that opening a file for write does not actually open the file you 74 | request. 75 | """ 76 | if 'a' in mode: 77 | raise IOError('append mode not supported for Git files') 78 | if '+' in mode: 79 | raise IOError('read/write mode not supported for Git files') 80 | if 'b' not in mode: 81 | raise IOError('text mode not supported for Git files') 82 | if 'w' in mode: 83 | return _GitFile(filename, mode, bufsize) 84 | else: 85 | return file(filename, mode, bufsize) 86 | 87 | 88 | class _GitFile(object): 89 | """File that follows the git locking protocol for writes. 90 | 91 | All writes to a file foo will be written into foo.lock in the same 92 | directory, and the lockfile will be renamed to overwrite the original file 93 | on close. 94 | 95 | :note: You *must* call close() or abort() on a _GitFile for the lock to be 96 | released. Typically this will happen in a finally block. 97 | """ 98 | 99 | PROXY_PROPERTIES = set(['closed', 'encoding', 'errors', 'mode', 'name', 100 | 'newlines', 'softspace']) 101 | PROXY_METHODS = ('__iter__', 'flush', 'fileno', 'isatty', 'next', 'read', 102 | 'readline', 'readlines', 'xreadlines', 'seek', 'tell', 103 | 'truncate', 'write', 'writelines') 104 | def __init__(self, filename, mode, bufsize): 105 | self._filename = filename 106 | self._lockfilename = '%s.lock' % self._filename 107 | fd = os.open(self._lockfilename, 108 | os.O_RDWR | os.O_CREAT | os.O_EXCL | getattr(os, "O_BINARY", 0)) 109 | self._file = os.fdopen(fd, mode, bufsize) 110 | self._closed = False 111 | 112 | for method in self.PROXY_METHODS: 113 | setattr(self, method, getattr(self._file, method)) 114 | 115 | def abort(self): 116 | """Close and discard the lockfile without overwriting the target. 117 | 118 | If the file is already closed, this is a no-op. 119 | """ 120 | if self._closed: 121 | return 122 | self._file.close() 123 | try: 124 | os.remove(self._lockfilename) 125 | self._closed = True 126 | except OSError, e: 127 | # The file may have been removed already, which is ok. 128 | if e.errno != errno.ENOENT: 129 | raise 130 | self._closed = True 131 | 132 | def close(self): 133 | """Close this file, saving the lockfile over the original. 134 | 135 | :note: If this method fails, it will attempt to delete the lockfile. 136 | However, it is not guaranteed to do so (e.g. if a filesystem becomes 137 | suddenly read-only), which will prevent future writes to this file 138 | until the lockfile is removed manually. 139 | :raises OSError: if the original file could not be overwritten. The lock 140 | file is still closed, so further attempts to write to the same file 141 | object will raise ValueError. 142 | """ 143 | if self._closed: 144 | return 145 | self._file.close() 146 | try: 147 | try: 148 | os.rename(self._lockfilename, self._filename) 149 | except OSError, e: 150 | # Windows versions prior to Vista don't support atomic renames 151 | if e.errno != errno.EEXIST: 152 | raise 153 | fancy_rename(self._lockfilename, self._filename) 154 | finally: 155 | self.abort() 156 | 157 | def __getattr__(self, name): 158 | """Proxy property calls to the underlying file.""" 159 | if name in self.PROXY_PROPERTIES: 160 | return getattr(self._file, name) 161 | raise AttributeError(name) 162 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/hooks.py: -------------------------------------------------------------------------------- 1 | # hooks.py -- for dealing with git hooks 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; version 2 6 | # of the License or (at your option) a later version of the License. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 16 | # MA 02110-1301, USA. 17 | 18 | """Access to hooks.""" 19 | 20 | import os 21 | import subprocess 22 | import tempfile 23 | import warnings 24 | 25 | from dulwich.errors import ( 26 | HookError, 27 | ) 28 | 29 | 30 | class Hook(object): 31 | """Generic hook object.""" 32 | 33 | def execute(elf, *args): 34 | """Execute the hook with the given args 35 | 36 | :param args: argument list to hook 37 | :raise HookError: hook execution failure 38 | :return: a hook may return a useful value 39 | """ 40 | raise NotImplementedError(self.execute) 41 | 42 | 43 | class ShellHook(Hook): 44 | """Hook by executable file 45 | 46 | Implements standard githooks(5) [0]: 47 | 48 | [0] http://www.kernel.org/pub/software/scm/git/docs/githooks.html 49 | """ 50 | 51 | def __init__(self, name, path, numparam, 52 | pre_exec_callback=None, post_exec_callback=None): 53 | """Setup shell hook definition 54 | 55 | :param name: name of hook for error messages 56 | :param path: absolute path to executable file 57 | :param numparam: number of requirements parameters 58 | :param pre_exec_callback: closure for setup before execution 59 | Defaults to None. Takes in the variable argument list from the 60 | execute functions and returns a modified argument list for the 61 | shell hook. 62 | :param post_exec_callback: closure for cleanup after execution 63 | Defaults to None. Takes in a boolean for hook success and the 64 | modified argument list and returns the final hook return value 65 | if applicable 66 | """ 67 | self.name = name 68 | self.filepath = path 69 | self.numparam = numparam 70 | 71 | self.pre_exec_callback = pre_exec_callback 72 | self.post_exec_callback = post_exec_callback 73 | 74 | def execute(self, *args): 75 | """Execute the hook with given args""" 76 | 77 | if len(args) != self.numparam: 78 | raise HookError("Hook %s executed with wrong number of args. \ 79 | Expected %d. Saw %d. %s" 80 | % (self.name, self.numparam, len(args))) 81 | 82 | if (self.pre_exec_callback is not None): 83 | args = self.pre_exec_callback(*args) 84 | 85 | try: 86 | ret = subprocess.call([self.filepath] + list(args)) 87 | if ret != 0: 88 | if (self.post_exec_callback is not None): 89 | self.post_exec_callback(0, *args) 90 | raise HookError("Hook %s exited with non-zero status" 91 | % (self.name)) 92 | if (self.post_exec_callback is not None): 93 | return self.post_exec_callback(1, *args) 94 | except OSError: # no file. silent failure. 95 | if (self.post_exec_callback is not None): 96 | self.post_exec_callback(0, *args) 97 | 98 | 99 | class PreCommitShellHook(ShellHook): 100 | """pre-commit shell hook""" 101 | 102 | def __init__(self, controldir): 103 | filepath = os.path.join(controldir, 'hooks', 'pre-commit') 104 | 105 | ShellHook.__init__(self, 'pre-commit', filepath, 0) 106 | 107 | 108 | class PostCommitShellHook(ShellHook): 109 | """post-commit shell hook""" 110 | 111 | def __init__(self, controldir): 112 | filepath = os.path.join(controldir, 'hooks', 'post-commit') 113 | 114 | ShellHook.__init__(self, 'post-commit', filepath, 0) 115 | 116 | 117 | class CommitMsgShellHook(ShellHook): 118 | """commit-msg shell hook 119 | 120 | :param args[0]: commit message 121 | :return: new commit message or None 122 | """ 123 | 124 | def __init__(self, controldir): 125 | filepath = os.path.join(controldir, 'hooks', 'commit-msg') 126 | 127 | def prepare_msg(*args): 128 | (fd, path) = tempfile.mkstemp() 129 | 130 | f = os.fdopen(fd, 'wb') 131 | try: 132 | f.write(args[0]) 133 | finally: 134 | f.close() 135 | 136 | return (path,) 137 | 138 | def clean_msg(success, *args): 139 | if success: 140 | with open(args[0], 'rb') as f: 141 | new_msg = f.read() 142 | os.unlink(args[0]) 143 | return new_msg 144 | os.unlink(args[0]) 145 | 146 | ShellHook.__init__(self, 'commit-msg', filepath, 1, 147 | prepare_msg, clean_msg) 148 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/log_utils.py: -------------------------------------------------------------------------------- 1 | # log_utils.py -- Logging utilities for Dulwich 2 | # Copyright (C) 2010 Google, Inc. 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | # Boston, MA 02110-1301, USA. 18 | 19 | """Logging utilities for Dulwich. 20 | 21 | Any module that uses logging needs to do compile-time initialization to set up 22 | the logging environment. Since Dulwich is also used as a library, clients may 23 | not want to see any logging output. In that case, we need to use a special 24 | handler to suppress spurious warnings like "No handlers could be found for 25 | logger dulwich.foo". 26 | 27 | For details on the _NullHandler approach, see: 28 | http://docs.python.org/library/logging.html#configuring-logging-for-a-library 29 | 30 | For many modules, the only function from the logging module they need is 31 | getLogger; this module exports that function for convenience. If a calling 32 | module needs something else, it can import the standard logging module directly. 33 | """ 34 | 35 | import logging 36 | import sys 37 | 38 | getLogger = logging.getLogger 39 | 40 | 41 | class _NullHandler(logging.Handler): 42 | """No-op logging handler to avoid unexpected logging warnings.""" 43 | 44 | def emit(self, record): 45 | pass 46 | 47 | 48 | _NULL_HANDLER = _NullHandler() 49 | _DULWICH_LOGGER = getLogger('dulwich') 50 | _DULWICH_LOGGER.addHandler(_NULL_HANDLER) 51 | 52 | 53 | def default_logging_config(): 54 | """Set up the default Dulwich loggers.""" 55 | remove_null_handler() 56 | logging.basicConfig(level=logging.INFO, stream=sys.stderr, 57 | format='%(asctime)s %(levelname)s: %(message)s') 58 | 59 | 60 | def remove_null_handler(): 61 | """Remove the null handler from the Dulwich loggers. 62 | 63 | If a caller wants to set up logging using something other than 64 | default_logging_config, calling this function first is a minor optimization 65 | to avoid the overhead of using the _NullHandler. 66 | """ 67 | _DULWICH_LOGGER.removeHandler(_NULL_HANDLER) 68 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/patch.py: -------------------------------------------------------------------------------- 1 | # patch.py -- For dealing with packed-style patches. 2 | # Copyright (C) 2009 Jelmer Vernooij 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # of the License or (at your option) a later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | # MA 02110-1301, USA. 18 | 19 | """Classes for dealing with git am-style patches. 20 | 21 | These patches are basically unified diffs with some extra metadata tacked 22 | on. 23 | """ 24 | 25 | from difflib import SequenceMatcher 26 | import rfc822 27 | import time 28 | 29 | from dulwich.objects import ( 30 | Commit, 31 | S_ISGITLINK, 32 | ) 33 | 34 | FIRST_FEW_BYTES = 8000 35 | 36 | 37 | def write_commit_patch(f, commit, contents, progress, version=None): 38 | """Write a individual file patch. 39 | 40 | :param commit: Commit object 41 | :param progress: Tuple with current patch number and total. 42 | :return: tuple with filename and contents 43 | """ 44 | (num, total) = progress 45 | f.write("From %s %s\n" % (commit.id, time.ctime(commit.commit_time))) 46 | f.write("From: %s\n" % commit.author) 47 | f.write("Date: %s\n" % time.strftime("%a, %d %b %Y %H:%M:%S %Z")) 48 | f.write("Subject: [PATCH %d/%d] %s\n" % (num, total, commit.message)) 49 | f.write("\n") 50 | f.write("---\n") 51 | try: 52 | import subprocess 53 | p = subprocess.Popen(["diffstat"], stdout=subprocess.PIPE, 54 | stdin=subprocess.PIPE) 55 | except (ImportError, OSError), e: 56 | pass # diffstat not available? 57 | else: 58 | (diffstat, _) = p.communicate(contents) 59 | f.write(diffstat) 60 | f.write("\n") 61 | f.write(contents) 62 | f.write("-- \n") 63 | if version is None: 64 | from dulwich import __version__ as dulwich_version 65 | f.write("Dulwich %d.%d.%d\n" % dulwich_version) 66 | else: 67 | f.write("%s\n" % version) 68 | 69 | 70 | def get_summary(commit): 71 | """Determine the summary line for use in a filename. 72 | 73 | :param commit: Commit 74 | :return: Summary string 75 | """ 76 | return commit.message.splitlines()[0].replace(" ", "-") 77 | 78 | 79 | def unified_diff(a, b, fromfile='', tofile='', n=3): 80 | """difflib.unified_diff that doesn't write any dates or trailing spaces. 81 | 82 | Based on the same function in Python2.6.5-rc2's difflib.py 83 | """ 84 | started = False 85 | for group in SequenceMatcher(None, a, b).get_grouped_opcodes(n): 86 | if not started: 87 | yield '--- %s\n' % fromfile 88 | yield '+++ %s\n' % tofile 89 | started = True 90 | i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4] 91 | yield "@@ -%d,%d +%d,%d @@\n" % (i1+1, i2-i1, j1+1, j2-j1) 92 | for tag, i1, i2, j1, j2 in group: 93 | if tag == 'equal': 94 | for line in a[i1:i2]: 95 | yield ' ' + line 96 | continue 97 | if tag == 'replace' or tag == 'delete': 98 | for line in a[i1:i2]: 99 | if not line[-1] == '\n': 100 | line += '\n\\ No newline at end of file\n' 101 | yield '-' + line 102 | if tag == 'replace' or tag == 'insert': 103 | for line in b[j1:j2]: 104 | if not line[-1] == '\n': 105 | line += '\n\\ No newline at end of file\n' 106 | yield '+' + line 107 | 108 | 109 | def is_binary(content): 110 | """See if the first few bytes contain any null characters. 111 | 112 | :param content: Bytestring to check for binary content 113 | """ 114 | return '\0' in content[:FIRST_FEW_BYTES] 115 | 116 | 117 | def write_object_diff(f, store, (old_path, old_mode, old_id), 118 | (new_path, new_mode, new_id), 119 | diff_binary=False): 120 | """Write the diff for an object. 121 | 122 | :param f: File-like object to write to 123 | :param store: Store to retrieve objects from, if necessary 124 | :param (old_path, old_mode, old_hexsha): Old file 125 | :param (new_path, new_mode, new_hexsha): New file 126 | :param diff_binary: Whether to diff files even if they 127 | are considered binary files by is_binary(). 128 | 129 | :note: the tuple elements should be None for nonexistant files 130 | """ 131 | def shortid(hexsha): 132 | if hexsha is None: 133 | return "0" * 7 134 | else: 135 | return hexsha[:7] 136 | 137 | def content(mode, hexsha): 138 | if hexsha is None: 139 | return '' 140 | elif S_ISGITLINK(mode): 141 | return "Submodule commit " + hexsha + "\n" 142 | else: 143 | return store[hexsha].data 144 | 145 | def lines(content): 146 | if not content: 147 | return [] 148 | else: 149 | return content.splitlines(True) 150 | 151 | if old_path is None: 152 | old_path = "/dev/null" 153 | else: 154 | old_path = "a/%s" % old_path 155 | if new_path is None: 156 | new_path = "/dev/null" 157 | else: 158 | new_path = "b/%s" % new_path 159 | f.write("diff --git %s %s\n" % (old_path, new_path)) 160 | if old_mode != new_mode: 161 | if new_mode is not None: 162 | if old_mode is not None: 163 | f.write("old mode %o\n" % old_mode) 164 | f.write("new mode %o\n" % new_mode) 165 | else: 166 | f.write("deleted mode %o\n" % old_mode) 167 | f.write("index %s..%s" % (shortid(old_id), shortid(new_id))) 168 | if new_mode is not None: 169 | f.write(" %o" % new_mode) 170 | f.write("\n") 171 | old_content = content(old_mode, old_id) 172 | new_content = content(new_mode, new_id) 173 | if not diff_binary and (is_binary(old_content) or is_binary(new_content)): 174 | f.write("Binary files %s and %s differ\n" % (old_path, new_path)) 175 | else: 176 | f.writelines(unified_diff(lines(old_content), lines(new_content), 177 | old_path, new_path)) 178 | 179 | 180 | def write_blob_diff(f, (old_path, old_mode, old_blob), 181 | (new_path, new_mode, new_blob)): 182 | """Write diff file header. 183 | 184 | :param f: File-like object to write to 185 | :param (old_path, old_mode, old_blob): Previous file (None if nonexisting) 186 | :param (new_path, new_mode, new_blob): New file (None if nonexisting) 187 | 188 | :note: The use of write_object_diff is recommended over this function. 189 | """ 190 | def blob_id(blob): 191 | if blob is None: 192 | return "0" * 7 193 | else: 194 | return blob.id[:7] 195 | def lines(blob): 196 | if blob is not None: 197 | return blob.data.splitlines(True) 198 | else: 199 | return [] 200 | if old_path is None: 201 | old_path = "/dev/null" 202 | else: 203 | old_path = "a/%s" % old_path 204 | if new_path is None: 205 | new_path = "/dev/null" 206 | else: 207 | new_path = "b/%s" % new_path 208 | f.write("diff --git %s %s\n" % (old_path, new_path)) 209 | if old_mode != new_mode: 210 | if new_mode is not None: 211 | if old_mode is not None: 212 | f.write("old mode %o\n" % old_mode) 213 | f.write("new mode %o\n" % new_mode) 214 | else: 215 | f.write("deleted mode %o\n" % old_mode) 216 | f.write("index %s..%s" % (blob_id(old_blob), blob_id(new_blob))) 217 | if new_mode is not None: 218 | f.write(" %o" % new_mode) 219 | f.write("\n") 220 | old_contents = lines(old_blob) 221 | new_contents = lines(new_blob) 222 | f.writelines(unified_diff(old_contents, new_contents, 223 | old_path, new_path)) 224 | 225 | 226 | def write_tree_diff(f, store, old_tree, new_tree, diff_binary=False): 227 | """Write tree diff. 228 | 229 | :param f: File-like object to write to. 230 | :param old_tree: Old tree id 231 | :param new_tree: New tree id 232 | :param diff_binary: Whether to diff files even if they 233 | are considered binary files by is_binary(). 234 | """ 235 | changes = store.tree_changes(old_tree, new_tree) 236 | for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes: 237 | write_object_diff(f, store, (oldpath, oldmode, oldsha), 238 | (newpath, newmode, newsha), 239 | diff_binary=diff_binary) 240 | 241 | 242 | def git_am_patch_split(f): 243 | """Parse a git-am-style patch and split it up into bits. 244 | 245 | :param f: File-like object to parse 246 | :return: Tuple with commit object, diff contents and git version 247 | """ 248 | msg = rfc822.Message(f) 249 | c = Commit() 250 | c.author = msg["from"] 251 | c.committer = msg["from"] 252 | try: 253 | patch_tag_start = msg["subject"].index("[PATCH") 254 | except ValueError: 255 | subject = msg["subject"] 256 | else: 257 | close = msg["subject"].index("] ", patch_tag_start) 258 | subject = msg["subject"][close+2:] 259 | c.message = subject.replace("\n", "") + "\n" 260 | first = True 261 | for l in f: 262 | if l == "---\n": 263 | break 264 | if first: 265 | if l.startswith("From: "): 266 | c.author = l[len("From: "):].rstrip() 267 | else: 268 | c.message += "\n" + l 269 | first = False 270 | else: 271 | c.message += l 272 | diff = "" 273 | for l in f: 274 | if l == "-- \n": 275 | break 276 | diff += l 277 | try: 278 | version = f.next().rstrip("\n") 279 | except StopIteration: 280 | version = None 281 | return c, diff, version 282 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # __init__.py -- The tests for dulwich 2 | # Copyright (C) 2007 James Westby 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # of the License or (at your option) any later version of 8 | # the License. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | # MA 02110-1301, USA. 19 | 20 | """Tests for Dulwich.""" 21 | 22 | import doctest 23 | import os 24 | import shutil 25 | import subprocess 26 | import sys 27 | import tempfile 28 | 29 | 30 | if sys.version_info >= (2, 7): 31 | # If Python itself provides an exception, use that 32 | import unittest 33 | from unittest import SkipTest, TestCase as _TestCase 34 | else: 35 | import unittest2 as unittest 36 | from unittest2 import SkipTest, TestCase as _TestCase 37 | 38 | 39 | def get_safe_env(env=None): 40 | """Returns the environment "env" (or a copy of "os.environ" by default) 41 | modified to avoid side-effects caused by user's ~/.gitconfig""" 42 | 43 | if env is None: 44 | env = os.environ.copy() 45 | # On Windows it's not enough to set "HOME" to a non-existing 46 | # directory. Git.cmd takes the first existing directory out of 47 | # "%HOME%", "%HOMEDRIVE%%HOMEPATH%" and "%USERPROFILE%". 48 | for e in 'HOME', 'HOMEPATH', 'USERPROFILE': 49 | env[e] = '/nosuchdir' 50 | return env 51 | 52 | 53 | class TestCase(_TestCase): 54 | 55 | def makeSafeEnv(self): 56 | """Create environment with homedirectory-related variables stripped. 57 | 58 | Modifies os.environ for the duration of a test case to avoid 59 | side-effects caused by the user's ~/.gitconfig and other 60 | files in their home directory. 61 | """ 62 | old_env = os.environ 63 | def restore(): 64 | os.environ = old_env 65 | self.addCleanup(restore) 66 | new_env = dict(os.environ) 67 | for e in ['HOME', 'HOMEPATH', 'USERPROFILE']: 68 | new_env[e] = '/nosuchdir' 69 | os.environ = new_env 70 | 71 | def setUp(self): 72 | super(TestCase, self).setUp() 73 | self.makeSafeEnv() 74 | 75 | 76 | class BlackboxTestCase(TestCase): 77 | """Blackbox testing.""" 78 | 79 | bin_directory = os.path.abspath(os.path.join(os.path.dirname(__file__), 80 | "..", "..", "bin")) 81 | 82 | def bin_path(self, name): 83 | """Determine the full path of a binary. 84 | 85 | :param name: Name of the script 86 | :return: Full path 87 | """ 88 | return os.path.join(self.bin_directory, name) 89 | 90 | def run_command(self, name, args): 91 | """Run a Dulwich command. 92 | 93 | :param name: Name of the command, as it exists in bin/ 94 | :param args: Arguments to the command 95 | """ 96 | env = dict(os.environ) 97 | env["PYTHONPATH"] = os.pathsep.join(sys.path) 98 | 99 | # Since they don't have any extensions, Windows can't recognize 100 | # executablility of the Python files in /bin. Even then, we'd have to 101 | # expect the user to set up file associations for .py files. 102 | # 103 | # Save us from all that headache and call python with the bin script. 104 | argv = [sys.executable, self.bin_path(name)] + args 105 | return subprocess.Popen(argv, 106 | stdout=subprocess.PIPE, 107 | stdin=subprocess.PIPE, stderr=subprocess.PIPE, 108 | universal_newlines=True, 109 | env=env) 110 | 111 | 112 | def self_test_suite(): 113 | names = [ 114 | 'blackbox', 115 | 'client', 116 | 'config', 117 | 'diff_tree', 118 | 'fastexport', 119 | 'file', 120 | 'hooks', 121 | 'index', 122 | 'lru_cache', 123 | 'objects', 124 | 'object_store', 125 | 'missing_obj_finder', 126 | 'pack', 127 | 'patch', 128 | 'protocol', 129 | 'repository', 130 | 'server', 131 | 'walk', 132 | 'web', 133 | ] 134 | module_names = ['dulwich.tests.test_' + name for name in names] 135 | loader = unittest.TestLoader() 136 | return loader.loadTestsFromNames(module_names) 137 | 138 | 139 | def tutorial_test_suite(): 140 | tutorial = [ 141 | 'introduction', 142 | 'repo', 143 | 'object-store', 144 | 'remote', 145 | 'conclusion', 146 | ] 147 | tutorial_files = ["../../docs/tutorial/%s.txt" % name for name in tutorial] 148 | def setup(test): 149 | test.__old_cwd = os.getcwd() 150 | test.__dulwich_tempdir = tempfile.mkdtemp() 151 | os.chdir(test.__dulwich_tempdir) 152 | def teardown(test): 153 | os.chdir(test.__old_cwd) 154 | shutil.rmtree(test.__dulwich_tempdir) 155 | return doctest.DocFileSuite(setUp=setup, tearDown=teardown, 156 | *tutorial_files) 157 | 158 | 159 | def nocompat_test_suite(): 160 | result = unittest.TestSuite() 161 | result.addTests(self_test_suite()) 162 | result.addTests(tutorial_test_suite()) 163 | return result 164 | 165 | 166 | def compat_test_suite(): 167 | result = unittest.TestSuite() 168 | from dulwich.tests.compat import test_suite as compat_test_suite 169 | result.addTests(compat_test_suite()) 170 | return result 171 | 172 | 173 | def test_suite(): 174 | result = unittest.TestSuite() 175 | result.addTests(self_test_suite()) 176 | result.addTests(tutorial_test_suite()) 177 | from dulwich.tests.compat import test_suite as compat_test_suite 178 | result.addTests(compat_test_suite()) 179 | return result 180 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_blackbox.py: -------------------------------------------------------------------------------- 1 | # test_blackbox.py -- blackbox tests 2 | # Copyright (C) 2010 Jelmer Vernooij 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # of the License or (at your option) a later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | # MA 02110-1301, USA. 18 | 19 | """Blackbox tests for Dulwich commands.""" 20 | 21 | import tempfile 22 | 23 | from dulwich.repo import ( 24 | Repo, 25 | ) 26 | from dulwich.tests import ( 27 | BlackboxTestCase, 28 | ) 29 | 30 | 31 | class GitReceivePackTests(BlackboxTestCase): 32 | """Blackbox tests for dul-receive-pack.""" 33 | 34 | def setUp(self): 35 | super(GitReceivePackTests, self).setUp() 36 | self.path = tempfile.mkdtemp() 37 | self.repo = Repo.init(self.path) 38 | 39 | def test_basic(self): 40 | process = self.run_command("dul-receive-pack", [self.path]) 41 | (stdout, stderr) = process.communicate("0000") 42 | self.assertEqual('', stderr) 43 | self.assertEqual('0000', stdout[-4:]) 44 | self.assertEqual(0, process.returncode) 45 | 46 | def test_missing_arg(self): 47 | process = self.run_command("dul-receive-pack", []) 48 | (stdout, stderr) = process.communicate() 49 | self.assertEqual('usage: dul-receive-pack \n', stderr) 50 | self.assertEqual('', stdout) 51 | self.assertEqual(1, process.returncode) 52 | 53 | 54 | class GitUploadPackTests(BlackboxTestCase): 55 | """Blackbox tests for dul-upload-pack.""" 56 | 57 | def setUp(self): 58 | super(GitUploadPackTests, self).setUp() 59 | self.path = tempfile.mkdtemp() 60 | self.repo = Repo.init(self.path) 61 | 62 | def test_missing_arg(self): 63 | process = self.run_command("dul-upload-pack", []) 64 | (stdout, stderr) = process.communicate() 65 | self.assertEqual('usage: dul-upload-pack \n', stderr) 66 | self.assertEqual('', stdout) 67 | self.assertEqual(1, process.returncode) 68 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_config.py: -------------------------------------------------------------------------------- 1 | # test_config.py -- Tests for reading and writing configuration files 2 | # Copyright (C) 2011 Jelmer Vernooij 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # or (at your option) a later version of the License. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | # MA 02110-1301, USA. 18 | 19 | """Tests for reading and writing configuration files.""" 20 | 21 | from cStringIO import StringIO 22 | from dulwich.config import ( 23 | ConfigDict, 24 | ConfigFile, 25 | StackedConfig, 26 | _check_section_name, 27 | _check_variable_name, 28 | _format_string, 29 | _escape_value, 30 | _parse_string, 31 | _unescape_value, 32 | ) 33 | from dulwich.tests import TestCase 34 | 35 | 36 | class ConfigFileTests(TestCase): 37 | 38 | def from_file(self, text): 39 | return ConfigFile.from_file(StringIO(text)) 40 | 41 | def test_empty(self): 42 | ConfigFile() 43 | 44 | def test_eq(self): 45 | self.assertEqual(ConfigFile(), ConfigFile()) 46 | 47 | def test_default_config(self): 48 | cf = self.from_file("""[core] 49 | repositoryformatversion = 0 50 | filemode = true 51 | bare = false 52 | logallrefupdates = true 53 | """) 54 | self.assertEqual(ConfigFile({("core", ): { 55 | "repositoryformatversion": "0", 56 | "filemode": "true", 57 | "bare": "false", 58 | "logallrefupdates": "true"}}), cf) 59 | 60 | def test_from_file_empty(self): 61 | cf = self.from_file("") 62 | self.assertEqual(ConfigFile(), cf) 63 | 64 | def test_empty_line_before_section(self): 65 | cf = self.from_file("\n[section]\n") 66 | self.assertEqual(ConfigFile({("section", ): {}}), cf) 67 | 68 | def test_comment_before_section(self): 69 | cf = self.from_file("# foo\n[section]\n") 70 | self.assertEqual(ConfigFile({("section", ): {}}), cf) 71 | 72 | def test_comment_after_section(self): 73 | cf = self.from_file("[section] # foo\n") 74 | self.assertEqual(ConfigFile({("section", ): {}}), cf) 75 | 76 | def test_comment_after_variable(self): 77 | cf = self.from_file("[section]\nbar= foo # a comment\n") 78 | self.assertEqual(ConfigFile({("section", ): {"bar": "foo"}}), cf) 79 | 80 | def test_from_file_section(self): 81 | cf = self.from_file("[core]\nfoo = bar\n") 82 | self.assertEqual("bar", cf.get(("core", ), "foo")) 83 | self.assertEqual("bar", cf.get(("core", "foo"), "foo")) 84 | 85 | def test_from_file_section_case_insensitive(self): 86 | cf = self.from_file("[cOre]\nfOo = bar\n") 87 | self.assertEqual("bar", cf.get(("core", ), "foo")) 88 | self.assertEqual("bar", cf.get(("core", "foo"), "foo")) 89 | 90 | def test_from_file_with_mixed_quoted(self): 91 | cf = self.from_file("[core]\nfoo = \"bar\"la\n") 92 | self.assertEqual("barla", cf.get(("core", ), "foo")) 93 | 94 | def test_from_file_with_open_quoted(self): 95 | self.assertRaises(ValueError, 96 | self.from_file, "[core]\nfoo = \"bar\n") 97 | 98 | def test_from_file_with_quotes(self): 99 | cf = self.from_file( 100 | "[core]\n" 101 | 'foo = " bar"\n') 102 | self.assertEqual(" bar", cf.get(("core", ), "foo")) 103 | 104 | def test_from_file_with_interrupted_line(self): 105 | cf = self.from_file( 106 | "[core]\n" 107 | 'foo = bar\\\n' 108 | ' la\n') 109 | self.assertEqual("barla", cf.get(("core", ), "foo")) 110 | 111 | def test_from_file_with_boolean_setting(self): 112 | cf = self.from_file( 113 | "[core]\n" 114 | 'foo\n') 115 | self.assertEqual("true", cf.get(("core", ), "foo")) 116 | 117 | def test_from_file_subsection(self): 118 | cf = self.from_file("[branch \"foo\"]\nfoo = bar\n") 119 | self.assertEqual("bar", cf.get(("branch", "foo"), "foo")) 120 | 121 | def test_from_file_subsection_invalid(self): 122 | self.assertRaises(ValueError, 123 | self.from_file, "[branch \"foo]\nfoo = bar\n") 124 | 125 | def test_from_file_subsection_not_quoted(self): 126 | cf = self.from_file("[branch.foo]\nfoo = bar\n") 127 | self.assertEqual("bar", cf.get(("branch", "foo"), "foo")) 128 | 129 | def test_write_to_file_empty(self): 130 | c = ConfigFile() 131 | f = StringIO() 132 | c.write_to_file(f) 133 | self.assertEqual("", f.getvalue()) 134 | 135 | def test_write_to_file_section(self): 136 | c = ConfigFile() 137 | c.set(("core", ), "foo", "bar") 138 | f = StringIO() 139 | c.write_to_file(f) 140 | self.assertEqual("[core]\n\tfoo = bar\n", f.getvalue()) 141 | 142 | def test_write_to_file_subsection(self): 143 | c = ConfigFile() 144 | c.set(("branch", "blie"), "foo", "bar") 145 | f = StringIO() 146 | c.write_to_file(f) 147 | self.assertEqual("[branch \"blie\"]\n\tfoo = bar\n", f.getvalue()) 148 | 149 | def test_same_line(self): 150 | cf = self.from_file("[branch.foo] foo = bar\n") 151 | self.assertEqual("bar", cf.get(("branch", "foo"), "foo")) 152 | 153 | 154 | class ConfigDictTests(TestCase): 155 | 156 | def test_get_set(self): 157 | cd = ConfigDict() 158 | self.assertRaises(KeyError, cd.get, "foo", "core") 159 | cd.set(("core", ), "foo", "bla") 160 | self.assertEqual("bla", cd.get(("core", ), "foo")) 161 | cd.set(("core", ), "foo", "bloe") 162 | self.assertEqual("bloe", cd.get(("core", ), "foo")) 163 | 164 | def test_get_boolean(self): 165 | cd = ConfigDict() 166 | cd.set(("core", ), "foo", "true") 167 | self.assertTrue(cd.get_boolean(("core", ), "foo")) 168 | cd.set(("core", ), "foo", "false") 169 | self.assertFalse(cd.get_boolean(("core", ), "foo")) 170 | cd.set(("core", ), "foo", "invalid") 171 | self.assertRaises(ValueError, cd.get_boolean, ("core", ), "foo") 172 | 173 | def test_dict(self): 174 | cd = ConfigDict() 175 | cd.set(("core", ), "foo", "bla") 176 | cd.set(("core2", ), "foo", "bloe") 177 | 178 | self.assertEqual([("core", ), ("core2", )], cd.keys()) 179 | self.assertEqual(cd[("core", )], {'foo': 'bla'}) 180 | 181 | cd['a'] = 'b' 182 | self.assertEqual(cd['a'], 'b') 183 | 184 | 185 | class StackedConfigTests(TestCase): 186 | 187 | def test_default_backends(self): 188 | StackedConfig.default_backends() 189 | 190 | 191 | class UnescapeTests(TestCase): 192 | 193 | def test_nothing(self): 194 | self.assertEqual("", _unescape_value("")) 195 | 196 | def test_tab(self): 197 | self.assertEqual("\tbar\t", _unescape_value("\\tbar\\t")) 198 | 199 | def test_newline(self): 200 | self.assertEqual("\nbar\t", _unescape_value("\\nbar\\t")) 201 | 202 | def test_quote(self): 203 | self.assertEqual("\"foo\"", _unescape_value("\\\"foo\\\"")) 204 | 205 | 206 | class EscapeValueTests(TestCase): 207 | 208 | def test_nothing(self): 209 | self.assertEqual("foo", _escape_value("foo")) 210 | 211 | def test_backslash(self): 212 | self.assertEqual("foo\\\\", _escape_value("foo\\")) 213 | 214 | def test_newline(self): 215 | self.assertEqual("foo\\n", _escape_value("foo\n")) 216 | 217 | 218 | class FormatStringTests(TestCase): 219 | 220 | def test_quoted(self): 221 | self.assertEqual('" foo"', _format_string(" foo")) 222 | self.assertEqual('"\\tfoo"', _format_string("\tfoo")) 223 | 224 | def test_not_quoted(self): 225 | self.assertEqual('foo', _format_string("foo")) 226 | self.assertEqual('foo bar', _format_string("foo bar")) 227 | 228 | 229 | class ParseStringTests(TestCase): 230 | 231 | def test_quoted(self): 232 | self.assertEqual(' foo', _parse_string('" foo"')) 233 | self.assertEqual('\tfoo', _parse_string('"\\tfoo"')) 234 | 235 | def test_not_quoted(self): 236 | self.assertEqual('foo', _parse_string("foo")) 237 | self.assertEqual('foo bar', _parse_string("foo bar")) 238 | 239 | 240 | class CheckVariableNameTests(TestCase): 241 | 242 | def test_invalid(self): 243 | self.assertFalse(_check_variable_name("foo ")) 244 | self.assertFalse(_check_variable_name("bar,bar")) 245 | self.assertFalse(_check_variable_name("bar.bar")) 246 | 247 | def test_valid(self): 248 | self.assertTrue(_check_variable_name("FOO")) 249 | self.assertTrue(_check_variable_name("foo")) 250 | self.assertTrue(_check_variable_name("foo-bar")) 251 | 252 | 253 | class CheckSectionNameTests(TestCase): 254 | 255 | def test_invalid(self): 256 | self.assertFalse(_check_section_name("foo ")) 257 | self.assertFalse(_check_section_name("bar,bar")) 258 | 259 | def test_valid(self): 260 | self.assertTrue(_check_section_name("FOO")) 261 | self.assertTrue(_check_section_name("foo")) 262 | self.assertTrue(_check_section_name("foo-bar")) 263 | self.assertTrue(_check_section_name("bar.bar")) 264 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_fastexport.py: -------------------------------------------------------------------------------- 1 | # test_fastexport.py -- Fast export/import functionality 2 | # Copyright (C) 2010 Jelmer Vernooij 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # of the License or (at your option) any later version of 8 | # the License. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | # MA 02110-1301, USA. 19 | 20 | from cStringIO import StringIO 21 | import stat 22 | 23 | from dulwich.object_store import ( 24 | MemoryObjectStore, 25 | ) 26 | from dulwich.objects import ( 27 | Blob, 28 | Commit, 29 | Tree, 30 | ) 31 | from dulwich.repo import ( 32 | MemoryRepo, 33 | ) 34 | from dulwich.tests import ( 35 | SkipTest, 36 | TestCase, 37 | ) 38 | 39 | 40 | class GitFastExporterTests(TestCase): 41 | """Tests for the GitFastExporter tests.""" 42 | 43 | def setUp(self): 44 | super(GitFastExporterTests, self).setUp() 45 | self.store = MemoryObjectStore() 46 | self.stream = StringIO() 47 | try: 48 | from dulwich.fastexport import GitFastExporter 49 | except ImportError: 50 | raise SkipTest("python-fastimport not available") 51 | self.fastexporter = GitFastExporter(self.stream, self.store) 52 | 53 | def test_emit_blob(self): 54 | b = Blob() 55 | b.data = "fooBAR" 56 | self.fastexporter.emit_blob(b) 57 | self.assertEqual('blob\nmark :1\ndata 6\nfooBAR\n', 58 | self.stream.getvalue()) 59 | 60 | def test_emit_commit(self): 61 | b = Blob() 62 | b.data = "FOO" 63 | t = Tree() 64 | t.add("foo", stat.S_IFREG | 0644, b.id) 65 | c = Commit() 66 | c.committer = c.author = "Jelmer " 67 | c.author_time = c.commit_time = 1271345553 68 | c.author_timezone = c.commit_timezone = 0 69 | c.message = "msg" 70 | c.tree = t.id 71 | self.store.add_objects([(b, None), (t, None), (c, None)]) 72 | self.fastexporter.emit_commit(c, "refs/heads/master") 73 | self.assertEqual("""blob 74 | mark :1 75 | data 3 76 | FOO 77 | commit refs/heads/master 78 | mark :2 79 | author Jelmer 1271345553 +0000 80 | committer Jelmer 1271345553 +0000 81 | data 3 82 | msg 83 | M 644 1 foo 84 | """, self.stream.getvalue()) 85 | 86 | 87 | class GitImportProcessorTests(TestCase): 88 | """Tests for the GitImportProcessor tests.""" 89 | 90 | def setUp(self): 91 | super(GitImportProcessorTests, self).setUp() 92 | self.repo = MemoryRepo() 93 | try: 94 | from dulwich.fastexport import GitImportProcessor 95 | except ImportError: 96 | raise SkipTest("python-fastimport not available") 97 | self.processor = GitImportProcessor(self.repo) 98 | 99 | def test_commit_handler(self): 100 | from fastimport import commands 101 | cmd = commands.CommitCommand("refs/heads/foo", "mrkr", 102 | ("Jelmer", "jelmer@samba.org", 432432432.0, 3600), 103 | ("Jelmer", "jelmer@samba.org", 432432432.0, 3600), 104 | "FOO", None, [], []) 105 | self.processor.commit_handler(cmd) 106 | commit = self.repo[self.processor.last_commit] 107 | self.assertEqual("Jelmer ", commit.author) 108 | self.assertEqual("Jelmer ", commit.committer) 109 | self.assertEqual("FOO", commit.message) 110 | self.assertEqual([], commit.parents) 111 | self.assertEqual(432432432.0, commit.commit_time) 112 | self.assertEqual(432432432.0, commit.author_time) 113 | self.assertEqual(3600, commit.commit_timezone) 114 | self.assertEqual(3600, commit.author_timezone) 115 | self.assertEqual(commit, self.repo["refs/heads/foo"]) 116 | 117 | def test_import_stream(self): 118 | markers = self.processor.import_stream(StringIO("""blob 119 | mark :1 120 | data 11 121 | text for a 122 | 123 | commit refs/heads/master 124 | mark :2 125 | committer Joe Foo 1288287382 +0000 126 | data 20 127 | 128 | M 100644 :1 a 129 | 130 | """)) 131 | self.assertEqual(2, len(markers)) 132 | self.assertTrue(isinstance(self.repo[markers["1"]], Blob)) 133 | self.assertTrue(isinstance(self.repo[markers["2"]], Commit)) 134 | 135 | def test_file_add(self): 136 | from fastimport import commands 137 | cmd = commands.BlobCommand("23", "data") 138 | self.processor.blob_handler(cmd) 139 | cmd = commands.CommitCommand("refs/heads/foo", "mrkr", 140 | ("Jelmer", "jelmer@samba.org", 432432432.0, 3600), 141 | ("Jelmer", "jelmer@samba.org", 432432432.0, 3600), 142 | "FOO", None, [], [commands.FileModifyCommand("path", 0100644, ":23", None)]) 143 | self.processor.commit_handler(cmd) 144 | commit = self.repo[self.processor.last_commit] 145 | self.assertEqual([ 146 | ('path', 0100644, '6320cd248dd8aeaab759d5871f8781b5c0505172')], 147 | self.repo[commit.tree].items()) 148 | 149 | def simple_commit(self): 150 | from fastimport import commands 151 | cmd = commands.BlobCommand("23", "data") 152 | self.processor.blob_handler(cmd) 153 | cmd = commands.CommitCommand("refs/heads/foo", "mrkr", 154 | ("Jelmer", "jelmer@samba.org", 432432432.0, 3600), 155 | ("Jelmer", "jelmer@samba.org", 432432432.0, 3600), 156 | "FOO", None, [], [commands.FileModifyCommand("path", 0100644, ":23", None)]) 157 | self.processor.commit_handler(cmd) 158 | commit = self.repo[self.processor.last_commit] 159 | return commit 160 | 161 | def make_file_commit(self, file_cmds): 162 | """Create a trivial commit with the specified file commands. 163 | 164 | :param file_cmds: File commands to run. 165 | :return: The created commit object 166 | """ 167 | from fastimport import commands 168 | cmd = commands.CommitCommand("refs/heads/foo", "mrkr", 169 | ("Jelmer", "jelmer@samba.org", 432432432.0, 3600), 170 | ("Jelmer", "jelmer@samba.org", 432432432.0, 3600), 171 | "FOO", None, [], file_cmds) 172 | self.processor.commit_handler(cmd) 173 | return self.repo[self.processor.last_commit] 174 | 175 | def test_file_copy(self): 176 | from fastimport import commands 177 | self.simple_commit() 178 | commit = self.make_file_commit([commands.FileCopyCommand("path", "new_path")]) 179 | self.assertEqual([ 180 | ('new_path', 0100644, '6320cd248dd8aeaab759d5871f8781b5c0505172'), 181 | ('path', 0100644, '6320cd248dd8aeaab759d5871f8781b5c0505172'), 182 | ], self.repo[commit.tree].items()) 183 | 184 | def test_file_move(self): 185 | from fastimport import commands 186 | self.simple_commit() 187 | commit = self.make_file_commit([commands.FileRenameCommand("path", "new_path")]) 188 | self.assertEqual([ 189 | ('new_path', 0100644, '6320cd248dd8aeaab759d5871f8781b5c0505172'), 190 | ], self.repo[commit.tree].items()) 191 | 192 | def test_file_delete(self): 193 | from fastimport import commands 194 | self.simple_commit() 195 | commit = self.make_file_commit([commands.FileDeleteCommand("path")]) 196 | self.assertEqual([], self.repo[commit.tree].items()) 197 | 198 | def test_file_deleteall(self): 199 | from fastimport import commands 200 | self.simple_commit() 201 | commit = self.make_file_commit([commands.FileDeleteAllCommand()]) 202 | self.assertEqual([], self.repo[commit.tree].items()) 203 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_file.py: -------------------------------------------------------------------------------- 1 | # test_file.py -- Test for git files 2 | # Copyright (C) 2010 Google, Inc. 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # of the License or (at your option) a later version of the License. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | # MA 02110-1301, USA. 18 | 19 | import errno 20 | import os 21 | import shutil 22 | import sys 23 | import tempfile 24 | 25 | from dulwich.file import GitFile, fancy_rename 26 | from dulwich.tests import ( 27 | SkipTest, 28 | TestCase, 29 | ) 30 | 31 | 32 | class FancyRenameTests(TestCase): 33 | 34 | def setUp(self): 35 | super(FancyRenameTests, self).setUp() 36 | self._tempdir = tempfile.mkdtemp() 37 | self.foo = self.path('foo') 38 | self.bar = self.path('bar') 39 | self.create(self.foo, 'foo contents') 40 | 41 | def tearDown(self): 42 | shutil.rmtree(self._tempdir) 43 | super(FancyRenameTests, self).tearDown() 44 | 45 | def path(self, filename): 46 | return os.path.join(self._tempdir, filename) 47 | 48 | def create(self, path, contents): 49 | f = open(path, 'wb') 50 | f.write(contents) 51 | f.close() 52 | 53 | def test_no_dest_exists(self): 54 | self.assertFalse(os.path.exists(self.bar)) 55 | fancy_rename(self.foo, self.bar) 56 | self.assertFalse(os.path.exists(self.foo)) 57 | 58 | new_f = open(self.bar, 'rb') 59 | self.assertEqual('foo contents', new_f.read()) 60 | new_f.close() 61 | 62 | def test_dest_exists(self): 63 | self.create(self.bar, 'bar contents') 64 | fancy_rename(self.foo, self.bar) 65 | self.assertFalse(os.path.exists(self.foo)) 66 | 67 | new_f = open(self.bar, 'rb') 68 | self.assertEqual('foo contents', new_f.read()) 69 | new_f.close() 70 | 71 | def test_dest_opened(self): 72 | if sys.platform != "win32": 73 | raise SkipTest("platform allows overwriting open files") 74 | self.create(self.bar, 'bar contents') 75 | dest_f = open(self.bar, 'rb') 76 | self.assertRaises(OSError, fancy_rename, self.foo, self.bar) 77 | dest_f.close() 78 | self.assertTrue(os.path.exists(self.path('foo'))) 79 | 80 | new_f = open(self.foo, 'rb') 81 | self.assertEqual('foo contents', new_f.read()) 82 | new_f.close() 83 | 84 | new_f = open(self.bar, 'rb') 85 | self.assertEqual('bar contents', new_f.read()) 86 | new_f.close() 87 | 88 | 89 | class GitFileTests(TestCase): 90 | 91 | def setUp(self): 92 | super(GitFileTests, self).setUp() 93 | self._tempdir = tempfile.mkdtemp() 94 | f = open(self.path('foo'), 'wb') 95 | f.write('foo contents') 96 | f.close() 97 | 98 | def tearDown(self): 99 | shutil.rmtree(self._tempdir) 100 | super(GitFileTests, self).tearDown() 101 | 102 | def path(self, filename): 103 | return os.path.join(self._tempdir, filename) 104 | 105 | def test_invalid(self): 106 | foo = self.path('foo') 107 | self.assertRaises(IOError, GitFile, foo, mode='r') 108 | self.assertRaises(IOError, GitFile, foo, mode='ab') 109 | self.assertRaises(IOError, GitFile, foo, mode='r+b') 110 | self.assertRaises(IOError, GitFile, foo, mode='w+b') 111 | self.assertRaises(IOError, GitFile, foo, mode='a+bU') 112 | 113 | def test_readonly(self): 114 | f = GitFile(self.path('foo'), 'rb') 115 | self.assertTrue(isinstance(f, file)) 116 | self.assertEqual('foo contents', f.read()) 117 | self.assertEqual('', f.read()) 118 | f.seek(4) 119 | self.assertEqual('contents', f.read()) 120 | f.close() 121 | 122 | def test_default_mode(self): 123 | f = GitFile(self.path('foo')) 124 | self.assertEqual('foo contents', f.read()) 125 | f.close() 126 | 127 | def test_write(self): 128 | foo = self.path('foo') 129 | foo_lock = '%s.lock' % foo 130 | 131 | orig_f = open(foo, 'rb') 132 | self.assertEqual(orig_f.read(), 'foo contents') 133 | orig_f.close() 134 | 135 | self.assertFalse(os.path.exists(foo_lock)) 136 | f = GitFile(foo, 'wb') 137 | self.assertFalse(f.closed) 138 | self.assertRaises(AttributeError, getattr, f, 'not_a_file_property') 139 | 140 | self.assertTrue(os.path.exists(foo_lock)) 141 | f.write('new stuff') 142 | f.seek(4) 143 | f.write('contents') 144 | f.close() 145 | self.assertFalse(os.path.exists(foo_lock)) 146 | 147 | new_f = open(foo, 'rb') 148 | self.assertEqual('new contents', new_f.read()) 149 | new_f.close() 150 | 151 | def test_open_twice(self): 152 | foo = self.path('foo') 153 | f1 = GitFile(foo, 'wb') 154 | f1.write('new') 155 | try: 156 | f2 = GitFile(foo, 'wb') 157 | self.fail() 158 | except OSError, e: 159 | self.assertEqual(errno.EEXIST, e.errno) 160 | f1.write(' contents') 161 | f1.close() 162 | 163 | # Ensure trying to open twice doesn't affect original. 164 | f = open(foo, 'rb') 165 | self.assertEqual('new contents', f.read()) 166 | f.close() 167 | 168 | def test_abort(self): 169 | foo = self.path('foo') 170 | foo_lock = '%s.lock' % foo 171 | 172 | orig_f = open(foo, 'rb') 173 | self.assertEqual(orig_f.read(), 'foo contents') 174 | orig_f.close() 175 | 176 | f = GitFile(foo, 'wb') 177 | f.write('new contents') 178 | f.abort() 179 | self.assertTrue(f.closed) 180 | self.assertFalse(os.path.exists(foo_lock)) 181 | 182 | new_orig_f = open(foo, 'rb') 183 | self.assertEqual(new_orig_f.read(), 'foo contents') 184 | new_orig_f.close() 185 | 186 | def test_abort_close(self): 187 | foo = self.path('foo') 188 | f = GitFile(foo, 'wb') 189 | f.abort() 190 | try: 191 | f.close() 192 | except (IOError, OSError): 193 | self.fail() 194 | 195 | f = GitFile(foo, 'wb') 196 | f.close() 197 | try: 198 | f.abort() 199 | except (IOError, OSError): 200 | self.fail() 201 | 202 | def test_abort_close_removed(self): 203 | foo = self.path('foo') 204 | f = GitFile(foo, 'wb') 205 | 206 | f._file.close() 207 | os.remove(foo+".lock") 208 | 209 | f.abort() 210 | self.assertTrue(f._closed) 211 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_hooks.py: -------------------------------------------------------------------------------- 1 | # test_hooks.py -- Tests for executing hooks 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # or (at your option) a later version of the License. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 16 | # MA 02110-1301, USA. 17 | 18 | """Tests for executing hooks.""" 19 | 20 | import os 21 | import stat 22 | import shutil 23 | import tempfile 24 | import warnings 25 | 26 | from dulwich import errors 27 | 28 | from dulwich.hooks import ( 29 | PreCommitShellHook, 30 | PostCommitShellHook, 31 | CommitMsgShellHook, 32 | ) 33 | 34 | from dulwich.tests import TestCase 35 | 36 | 37 | class ShellHookTests(TestCase): 38 | 39 | def setUp(self): 40 | if os.name != 'posix': 41 | self.skipTest('shell hook tests requires POSIX shell') 42 | 43 | def test_hook_pre_commit(self): 44 | pre_commit_fail = """#!/bin/sh 45 | exit 1 46 | """ 47 | 48 | pre_commit_success = """#!/bin/sh 49 | exit 0 50 | """ 51 | 52 | repo_dir = os.path.join(tempfile.mkdtemp()) 53 | os.mkdir(os.path.join(repo_dir, 'hooks')) 54 | self.addCleanup(shutil.rmtree, repo_dir) 55 | 56 | pre_commit = os.path.join(repo_dir, 'hooks', 'pre-commit') 57 | hook = PreCommitShellHook(repo_dir) 58 | 59 | f = open(pre_commit, 'wb') 60 | try: 61 | f.write(pre_commit_fail) 62 | finally: 63 | f.close() 64 | os.chmod(pre_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) 65 | 66 | self.assertRaises(errors.HookError, hook.execute) 67 | 68 | f = open(pre_commit, 'wb') 69 | try: 70 | f.write(pre_commit_success) 71 | finally: 72 | f.close() 73 | os.chmod(pre_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) 74 | 75 | hook.execute() 76 | 77 | def test_hook_commit_msg(self): 78 | 79 | commit_msg_fail = """#!/bin/sh 80 | exit 1 81 | """ 82 | 83 | commit_msg_success = """#!/bin/sh 84 | exit 0 85 | """ 86 | 87 | repo_dir = os.path.join(tempfile.mkdtemp()) 88 | os.mkdir(os.path.join(repo_dir, 'hooks')) 89 | self.addCleanup(shutil.rmtree, repo_dir) 90 | 91 | commit_msg = os.path.join(repo_dir, 'hooks', 'commit-msg') 92 | hook = CommitMsgShellHook(repo_dir) 93 | 94 | f = open(commit_msg, 'wb') 95 | try: 96 | f.write(commit_msg_fail) 97 | finally: 98 | f.close() 99 | os.chmod(commit_msg, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) 100 | 101 | self.assertRaises(errors.HookError, hook.execute, 'failed commit') 102 | 103 | f = open(commit_msg, 'wb') 104 | try: 105 | f.write(commit_msg_success) 106 | finally: 107 | f.close() 108 | os.chmod(commit_msg, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) 109 | 110 | hook.execute('empty commit') 111 | 112 | def test_hook_post_commit(self): 113 | 114 | (fd, path) = tempfile.mkstemp() 115 | post_commit_msg = """#!/bin/sh 116 | unlink %(file)s 117 | """ % {'file': path} 118 | 119 | post_commit_msg_fail = """#!/bin/sh 120 | exit 1 121 | """ 122 | 123 | repo_dir = os.path.join(tempfile.mkdtemp()) 124 | os.mkdir(os.path.join(repo_dir, 'hooks')) 125 | self.addCleanup(shutil.rmtree, repo_dir) 126 | 127 | post_commit = os.path.join(repo_dir, 'hooks', 'post-commit') 128 | hook = PostCommitShellHook(repo_dir) 129 | 130 | f = open(post_commit, 'wb') 131 | try: 132 | f.write(post_commit_msg_fail) 133 | finally: 134 | f.close() 135 | os.chmod(post_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) 136 | 137 | self.assertRaises(errors.HookError, hook.execute) 138 | 139 | f = open(post_commit, 'wb') 140 | try: 141 | f.write(post_commit_msg) 142 | finally: 143 | f.close() 144 | os.chmod(post_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) 145 | 146 | hook.execute() 147 | self.assertFalse(os.path.exists(path)) 148 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_index.py: -------------------------------------------------------------------------------- 1 | # test_index.py -- Tests for the git index 2 | # Copyright (C) 2008-2009 Jelmer Vernooij 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # or (at your option) any later version of the License. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | # MA 02110-1301, USA. 18 | 19 | """Tests for the index.""" 20 | 21 | 22 | from cStringIO import ( 23 | StringIO, 24 | ) 25 | import os 26 | import shutil 27 | import stat 28 | import struct 29 | import tempfile 30 | 31 | from dulwich.index import ( 32 | Index, 33 | build_index_from_tree, 34 | cleanup_mode, 35 | commit_tree, 36 | index_entry_from_stat, 37 | read_index, 38 | write_cache_time, 39 | write_index, 40 | ) 41 | from dulwich.object_store import ( 42 | MemoryObjectStore, 43 | ) 44 | from dulwich.objects import ( 45 | Blob, 46 | Tree, 47 | ) 48 | from dulwich.repo import Repo 49 | from dulwich.tests import TestCase 50 | 51 | 52 | class IndexTestCase(TestCase): 53 | 54 | datadir = os.path.join(os.path.dirname(__file__), 'data/indexes') 55 | 56 | def get_simple_index(self, name): 57 | return Index(os.path.join(self.datadir, name)) 58 | 59 | 60 | class SimpleIndexTestCase(IndexTestCase): 61 | 62 | def test_len(self): 63 | self.assertEqual(1, len(self.get_simple_index("index"))) 64 | 65 | def test_iter(self): 66 | self.assertEqual(['bla'], list(self.get_simple_index("index"))) 67 | 68 | def test_getitem(self): 69 | self.assertEqual(((1230680220, 0), (1230680220, 0), 2050, 3761020, 70 | 33188, 1000, 1000, 0, 71 | 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391', 0), 72 | self.get_simple_index("index")["bla"]) 73 | 74 | def test_empty(self): 75 | i = self.get_simple_index("notanindex") 76 | self.assertEqual(0, len(i)) 77 | self.assertFalse(os.path.exists(i._filename)) 78 | 79 | def test_against_empty_tree(self): 80 | i = self.get_simple_index("index") 81 | changes = list(i.changes_from_tree(MemoryObjectStore(), None)) 82 | self.assertEqual(1, len(changes)) 83 | (oldname, newname), (oldmode, newmode), (oldsha, newsha) = changes[0] 84 | self.assertEqual('bla', newname) 85 | self.assertEqual('e69de29bb2d1d6434b8b29ae775ad8c2e48c5391', newsha) 86 | 87 | class SimpleIndexWriterTestCase(IndexTestCase): 88 | 89 | def setUp(self): 90 | IndexTestCase.setUp(self) 91 | self.tempdir = tempfile.mkdtemp() 92 | 93 | def tearDown(self): 94 | IndexTestCase.tearDown(self) 95 | shutil.rmtree(self.tempdir) 96 | 97 | def test_simple_write(self): 98 | entries = [('barbla', (1230680220, 0), (1230680220, 0), 2050, 3761020, 99 | 33188, 1000, 1000, 0, 100 | 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391', 0)] 101 | filename = os.path.join(self.tempdir, 'test-simple-write-index') 102 | x = open(filename, 'w+') 103 | try: 104 | write_index(x, entries) 105 | finally: 106 | x.close() 107 | x = open(filename, 'r') 108 | try: 109 | self.assertEqual(entries, list(read_index(x))) 110 | finally: 111 | x.close() 112 | 113 | 114 | class CommitTreeTests(TestCase): 115 | 116 | def setUp(self): 117 | super(CommitTreeTests, self).setUp() 118 | self.store = MemoryObjectStore() 119 | 120 | def test_single_blob(self): 121 | blob = Blob() 122 | blob.data = "foo" 123 | self.store.add_object(blob) 124 | blobs = [("bla", blob.id, stat.S_IFREG)] 125 | rootid = commit_tree(self.store, blobs) 126 | self.assertEqual(rootid, "1a1e80437220f9312e855c37ac4398b68e5c1d50") 127 | self.assertEqual((stat.S_IFREG, blob.id), self.store[rootid]["bla"]) 128 | self.assertEqual(set([rootid, blob.id]), set(self.store._data.keys())) 129 | 130 | def test_nested(self): 131 | blob = Blob() 132 | blob.data = "foo" 133 | self.store.add_object(blob) 134 | blobs = [("bla/bar", blob.id, stat.S_IFREG)] 135 | rootid = commit_tree(self.store, blobs) 136 | self.assertEqual(rootid, "d92b959b216ad0d044671981196781b3258fa537") 137 | dirid = self.store[rootid]["bla"][1] 138 | self.assertEqual(dirid, "c1a1deb9788150829579a8b4efa6311e7b638650") 139 | self.assertEqual((stat.S_IFDIR, dirid), self.store[rootid]["bla"]) 140 | self.assertEqual((stat.S_IFREG, blob.id), self.store[dirid]["bar"]) 141 | self.assertEqual(set([rootid, dirid, blob.id]), 142 | set(self.store._data.keys())) 143 | 144 | 145 | class CleanupModeTests(TestCase): 146 | 147 | def test_file(self): 148 | self.assertEqual(0100644, cleanup_mode(0100000)) 149 | 150 | def test_executable(self): 151 | self.assertEqual(0100755, cleanup_mode(0100711)) 152 | 153 | def test_symlink(self): 154 | self.assertEqual(0120000, cleanup_mode(0120711)) 155 | 156 | def test_dir(self): 157 | self.assertEqual(0040000, cleanup_mode(040531)) 158 | 159 | def test_submodule(self): 160 | self.assertEqual(0160000, cleanup_mode(0160744)) 161 | 162 | 163 | class WriteCacheTimeTests(TestCase): 164 | 165 | def test_write_string(self): 166 | f = StringIO() 167 | self.assertRaises(TypeError, write_cache_time, f, "foo") 168 | 169 | def test_write_int(self): 170 | f = StringIO() 171 | write_cache_time(f, 434343) 172 | self.assertEqual(struct.pack(">LL", 434343, 0), f.getvalue()) 173 | 174 | def test_write_tuple(self): 175 | f = StringIO() 176 | write_cache_time(f, (434343, 21)) 177 | self.assertEqual(struct.pack(">LL", 434343, 21), f.getvalue()) 178 | 179 | def test_write_float(self): 180 | f = StringIO() 181 | write_cache_time(f, 434343.000000021) 182 | self.assertEqual(struct.pack(">LL", 434343, 21), f.getvalue()) 183 | 184 | 185 | class IndexEntryFromStatTests(TestCase): 186 | 187 | def test_simple(self): 188 | st = os.stat_result((16877, 131078, 64769L, 189 | 154, 1000, 1000, 12288, 190 | 1323629595, 1324180496, 1324180496)) 191 | entry = index_entry_from_stat(st, "22" * 20, 0) 192 | self.assertEqual(entry, ( 193 | 1324180496, 194 | 1324180496, 195 | 64769L, 196 | 131078, 197 | 16384, 198 | 1000, 199 | 1000, 200 | 12288, 201 | '2222222222222222222222222222222222222222', 202 | 0)) 203 | 204 | def test_override_mode(self): 205 | st = os.stat_result((stat.S_IFREG + 0644, 131078, 64769L, 206 | 154, 1000, 1000, 12288, 207 | 1323629595, 1324180496, 1324180496)) 208 | entry = index_entry_from_stat(st, "22" * 20, 0, 209 | mode=stat.S_IFREG + 0755) 210 | self.assertEqual(entry, ( 211 | 1324180496, 212 | 1324180496, 213 | 64769L, 214 | 131078, 215 | 33261, 216 | 1000, 217 | 1000, 218 | 12288, 219 | '2222222222222222222222222222222222222222', 220 | 0)) 221 | 222 | 223 | class BuildIndexTests(TestCase): 224 | 225 | def assertReasonableIndexEntry(self, index_entry, mode, filesize, sha): 226 | self.assertEquals(index_entry[4], mode) # mode 227 | self.assertEquals(index_entry[7], filesize) # filesize 228 | self.assertEquals(index_entry[8], sha) # sha 229 | 230 | def assertFileContents(self, path, contents, symlink=False): 231 | if symlink: 232 | self.assertEquals(os.readlink(path), contents) 233 | else: 234 | f = open(path, 'rb') 235 | try: 236 | self.assertEquals(f.read(), contents) 237 | finally: 238 | f.close() 239 | 240 | def test_empty(self): 241 | repo_dir = tempfile.mkdtemp() 242 | repo = Repo.init(repo_dir) 243 | self.addCleanup(shutil.rmtree, repo_dir) 244 | 245 | tree = Tree() 246 | repo.object_store.add_object(tree) 247 | 248 | build_index_from_tree(repo.path, repo.index_path(), 249 | repo.object_store, tree.id) 250 | 251 | # Verify index entries 252 | index = repo.open_index() 253 | self.assertEquals(len(index), 0) 254 | 255 | # Verify no files 256 | self.assertEquals(['.git'], os.listdir(repo.path)) 257 | 258 | def test_nonempty(self): 259 | if os.name != 'posix': 260 | self.skipTest("test depends on POSIX shell") 261 | 262 | repo_dir = tempfile.mkdtemp() 263 | repo = Repo.init(repo_dir) 264 | self.addCleanup(shutil.rmtree, repo_dir) 265 | 266 | # Populate repo 267 | filea = Blob.from_string('file a') 268 | fileb = Blob.from_string('file b') 269 | filed = Blob.from_string('file d') 270 | filee = Blob.from_string('d') 271 | 272 | tree = Tree() 273 | tree['a'] = (stat.S_IFREG | 0644, filea.id) 274 | tree['b'] = (stat.S_IFREG | 0644, fileb.id) 275 | tree['c/d'] = (stat.S_IFREG | 0644, filed.id) 276 | tree['c/e'] = (stat.S_IFLNK, filee.id) # symlink 277 | 278 | repo.object_store.add_objects([(o, None) 279 | for o in [filea, fileb, filed, filee, tree]]) 280 | 281 | build_index_from_tree(repo.path, repo.index_path(), 282 | repo.object_store, tree.id) 283 | 284 | # Verify index entries 285 | index = repo.open_index() 286 | self.assertEquals(len(index), 4) 287 | 288 | # filea 289 | apath = os.path.join(repo.path, 'a') 290 | self.assertTrue(os.path.exists(apath)) 291 | self.assertReasonableIndexEntry(index['a'], 292 | stat.S_IFREG | 0644, 6, filea.id) 293 | self.assertFileContents(apath, 'file a') 294 | 295 | # fileb 296 | bpath = os.path.join(repo.path, 'b') 297 | self.assertTrue(os.path.exists(bpath)) 298 | self.assertReasonableIndexEntry(index['b'], 299 | stat.S_IFREG | 0644, 6, fileb.id) 300 | self.assertFileContents(bpath, 'file b') 301 | 302 | # filed 303 | dpath = os.path.join(repo.path, 'c', 'd') 304 | self.assertTrue(os.path.exists(dpath)) 305 | self.assertReasonableIndexEntry(index['c/d'], 306 | stat.S_IFREG | 0644, 6, filed.id) 307 | self.assertFileContents(dpath, 'file d') 308 | 309 | # symlink to d 310 | epath = os.path.join(repo.path, 'c', 'e') 311 | self.assertTrue(os.path.exists(epath)) 312 | self.assertReasonableIndexEntry(index['c/e'], 313 | stat.S_IFLNK, 1, filee.id) 314 | self.assertFileContents(epath, 'd', symlink=True) 315 | 316 | # Verify no extra files 317 | self.assertEquals(['.git', 'a', 'b', 'c'], 318 | sorted(os.listdir(repo.path))) 319 | self.assertEquals(['d', 'e'], 320 | sorted(os.listdir(os.path.join(repo.path, 'c')))) 321 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_missing_obj_finder.py: -------------------------------------------------------------------------------- 1 | # test_missing_obj_finder.py -- tests for MissingObjectFinder 2 | # Copyright (C) 2012 syntevo GmbH 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # or (at your option) any later version of the License. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | # MA 02110-1301, USA. 18 | 19 | from dulwich.object_store import ( 20 | MemoryObjectStore, 21 | ) 22 | from dulwich.objects import ( 23 | Blob, 24 | ) 25 | from dulwich.tests import TestCase 26 | from utils import ( 27 | make_object, 28 | build_commit_graph, 29 | ) 30 | 31 | 32 | class MissingObjectFinderTest(TestCase): 33 | 34 | def setUp(self): 35 | super(MissingObjectFinderTest, self).setUp() 36 | self.store = MemoryObjectStore() 37 | self.commits = [] 38 | 39 | def cmt(self, n): 40 | return self.commits[n-1] 41 | 42 | def assertMissingMatch(self, haves, wants, expected): 43 | for sha, path in self.store.find_missing_objects(haves, wants): 44 | self.assertTrue(sha in expected, 45 | "(%s,%s) erroneously reported as missing" % (sha, path)) 46 | expected.remove(sha) 47 | 48 | self.assertEquals(len(expected), 0, 49 | "some objects are not reported as missing: %s" % (expected, )) 50 | 51 | 52 | class MOFLinearRepoTest(MissingObjectFinderTest): 53 | 54 | def setUp(self): 55 | super(MOFLinearRepoTest, self).setUp() 56 | f1_1 = make_object(Blob, data='f1') # present in 1, removed in 3 57 | f2_1 = make_object(Blob, data='f2') # present in all revisions, changed in 2 and 3 58 | f2_2 = make_object(Blob, data='f2-changed') 59 | f2_3 = make_object(Blob, data='f2-changed-again') 60 | f3_2 = make_object(Blob, data='f3') # added in 2, left unmodified in 3 61 | 62 | commit_spec = [[1], [2, 1], [3, 2]] 63 | trees = {1: [('f1', f1_1), ('f2', f2_1)], 64 | 2: [('f1', f1_1), ('f2', f2_2), ('f3', f3_2)], 65 | 3: [('f2', f2_3), ('f3', f3_2)] } 66 | # commit 1: f1 and f2 67 | # commit 2: f3 added, f2 changed. Missing shall report commit id and a 68 | # tree referenced by commit 69 | # commit 3: f1 removed, f2 changed. Commit sha and root tree sha shall 70 | # be reported as modified 71 | self.commits = build_commit_graph(self.store, commit_spec, trees) 72 | self.missing_1_2 = [self.cmt(2).id, self.cmt(2).tree, f2_2.id, f3_2.id] 73 | self.missing_2_3 = [self.cmt(3).id, self.cmt(3).tree, f2_3.id] 74 | self.missing_1_3 = [ 75 | self.cmt(2).id, self.cmt(3).id, 76 | self.cmt(2).tree, self.cmt(3).tree, 77 | f2_2.id, f3_2.id, f2_3.id] 78 | 79 | def test_1_to_2(self): 80 | self.assertMissingMatch([self.cmt(1).id], [self.cmt(2).id], 81 | self.missing_1_2) 82 | 83 | def test_2_to_3(self): 84 | self.assertMissingMatch([self.cmt(2).id], [self.cmt(3).id], 85 | self.missing_2_3) 86 | 87 | def test_1_to_3(self): 88 | self.assertMissingMatch([self.cmt(1).id], [self.cmt(3).id], 89 | self.missing_1_3) 90 | 91 | def test_bogus_haves_failure(self): 92 | """Ensure non-existent SHA in haves are not tolerated""" 93 | bogus_sha = self.cmt(2).id[::-1] 94 | haves = [self.cmt(1).id, bogus_sha] 95 | wants = [self.cmt(3).id] 96 | self.assertRaises(KeyError, self.store.find_missing_objects, 97 | self.store, haves, wants) 98 | 99 | def test_bogus_wants_failure(self): 100 | """Ensure non-existent SHA in wants are not tolerated""" 101 | bogus_sha = self.cmt(2).id[::-1] 102 | haves = [self.cmt(1).id] 103 | wants = [self.cmt(3).id, bogus_sha] 104 | self.assertRaises(KeyError, self.store.find_missing_objects, 105 | self.store, haves, wants) 106 | 107 | def test_no_changes(self): 108 | self.assertMissingMatch([self.cmt(3).id], [self.cmt(3).id], []) 109 | 110 | 111 | class MOFMergeForkRepoTest(MissingObjectFinderTest): 112 | # 1 --- 2 --- 4 --- 6 --- 7 113 | # \ / 114 | # 3 --- 115 | # \ 116 | # 5 117 | 118 | def setUp(self): 119 | super(MOFMergeForkRepoTest, self).setUp() 120 | f1_1 = make_object(Blob, data='f1') 121 | f1_2 = make_object(Blob, data='f1-2') 122 | f1_4 = make_object(Blob, data='f1-4') 123 | f1_7 = make_object(Blob, data='f1-2') # same data as in rev 2 124 | f2_1 = make_object(Blob, data='f2') 125 | f2_3 = make_object(Blob, data='f2-3') 126 | f3_3 = make_object(Blob, data='f3') 127 | f3_5 = make_object(Blob, data='f3-5') 128 | commit_spec = [[1], [2, 1], [3, 2], [4, 2], [5, 3], [6, 3, 4], [7, 6]] 129 | trees = {1: [('f1', f1_1), ('f2', f2_1)], 130 | 2: [('f1', f1_2), ('f2', f2_1)], # f1 changed 131 | # f3 added, f2 changed 132 | 3: [('f1', f1_2), ('f2', f2_3), ('f3', f3_3)], 133 | 4: [('f1', f1_4), ('f2', f2_1)], # f1 changed 134 | 5: [('f1', f1_2), ('f3', f3_5)], # f2 removed, f3 changed 135 | 6: [('f1', f1_4), ('f2', f2_3), ('f3', f3_3)], # merged 3 and 4 136 | # f1 changed to match rev2. f3 removed 137 | 7: [('f1', f1_7), ('f2', f2_3)]} 138 | self.commits = build_commit_graph(self.store, commit_spec, trees) 139 | 140 | self.f1_2_id = f1_2.id 141 | self.f1_4_id = f1_4.id 142 | self.f1_7_id = f1_7.id 143 | self.f2_3_id = f2_3.id 144 | self.f3_3_id = f3_3.id 145 | 146 | self.assertEquals(f1_2.id, f1_7.id, "[sanity]") 147 | 148 | def test_have6_want7(self): 149 | # have 6, want 7. Ideally, shall not report f1_7 as it's the same as 150 | # f1_2, however, to do so, MissingObjectFinder shall not record trees 151 | # of common commits only, but also all parent trees and tree items, 152 | # which is an overkill (i.e. in sha_done it records f1_4 as known, and 153 | # doesn't record f1_2 was known prior to that, hence can't detect f1_7 154 | # is in fact f1_2 and shall not be reported) 155 | self.assertMissingMatch([self.cmt(6).id], [self.cmt(7).id], 156 | [self.cmt(7).id, self.cmt(7).tree, self.f1_7_id]) 157 | 158 | def test_have4_want7(self): 159 | # have 4, want 7. Shall not include rev5 as it is not in the tree 160 | # between 4 and 7 (well, it is, but its SHA's are irrelevant for 4..7 161 | # commit hierarchy) 162 | self.assertMissingMatch([self.cmt(4).id], [self.cmt(7).id], [ 163 | self.cmt(7).id, self.cmt(6).id, self.cmt(3).id, 164 | self.cmt(7).tree, self.cmt(6).tree, self.cmt(3).tree, 165 | self.f2_3_id, self.f3_3_id]) 166 | 167 | def test_have1_want6(self): 168 | # have 1, want 6. Shall not include rev5 169 | self.assertMissingMatch([self.cmt(1).id], [self.cmt(6).id], [ 170 | self.cmt(6).id, self.cmt(4).id, self.cmt(3).id, self.cmt(2).id, 171 | self.cmt(6).tree, self.cmt(4).tree, self.cmt(3).tree, 172 | self.cmt(2).tree, self.f1_2_id, self.f1_4_id, self.f2_3_id, 173 | self.f3_3_id]) 174 | 175 | def test_have3_want6(self): 176 | # have 3, want 7. Shall not report rev2 and its tree, because 177 | # haves(3) means has parents, i.e. rev2, too 178 | # BUT shall report any changes descending rev2 (excluding rev3) 179 | # Shall NOT report f1_7 as it's techically == f1_2 180 | self.assertMissingMatch([self.cmt(3).id], [self.cmt(7).id], [ 181 | self.cmt(7).id, self.cmt(6).id, self.cmt(4).id, 182 | self.cmt(7).tree, self.cmt(6).tree, self.cmt(4).tree, 183 | self.f1_4_id]) 184 | 185 | def test_have5_want7(self): 186 | # have 5, want 7. Common parent is rev2, hence children of rev2 from 187 | # a descent line other than rev5 shall be reported 188 | # expects f1_4 from rev6. f3_5 is known in rev5; 189 | # f1_7 shall be the same as f1_2 (known, too) 190 | self.assertMissingMatch([self.cmt(5).id], [self.cmt(7).id], [ 191 | self.cmt(7).id, self.cmt(6).id, self.cmt(4).id, 192 | self.cmt(7).tree, self.cmt(6).tree, self.cmt(4).tree, 193 | self.f1_4_id]) 194 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_protocol.py: -------------------------------------------------------------------------------- 1 | # test_protocol.py -- Tests for the git protocol 2 | # Copyright (C) 2009 Jelmer Vernooij 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # or (at your option) any later version of the License. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | # MA 02110-1301, USA. 18 | 19 | """Tests for the smart protocol utility functions.""" 20 | 21 | 22 | from StringIO import StringIO 23 | 24 | from dulwich.errors import ( 25 | HangupException, 26 | ) 27 | from dulwich.protocol import ( 28 | PktLineParser, 29 | Protocol, 30 | ReceivableProtocol, 31 | extract_capabilities, 32 | extract_want_line_capabilities, 33 | ack_type, 34 | SINGLE_ACK, 35 | MULTI_ACK, 36 | MULTI_ACK_DETAILED, 37 | BufferedPktLineWriter, 38 | ) 39 | from dulwich.tests import TestCase 40 | 41 | 42 | class BaseProtocolTests(object): 43 | 44 | def test_write_pkt_line_none(self): 45 | self.proto.write_pkt_line(None) 46 | self.assertEqual(self.rout.getvalue(), '0000') 47 | 48 | def test_write_pkt_line(self): 49 | self.proto.write_pkt_line('bla') 50 | self.assertEqual(self.rout.getvalue(), '0007bla') 51 | 52 | def test_read_pkt_line(self): 53 | self.rin.write('0008cmd ') 54 | self.rin.seek(0) 55 | self.assertEqual('cmd ', self.proto.read_pkt_line()) 56 | 57 | def test_eof(self): 58 | self.rin.write('0000') 59 | self.rin.seek(0) 60 | self.assertFalse(self.proto.eof()) 61 | self.assertEqual(None, self.proto.read_pkt_line()) 62 | self.assertTrue(self.proto.eof()) 63 | self.assertRaises(HangupException, self.proto.read_pkt_line) 64 | 65 | def test_unread_pkt_line(self): 66 | self.rin.write('0007foo0000') 67 | self.rin.seek(0) 68 | self.assertEqual('foo', self.proto.read_pkt_line()) 69 | self.proto.unread_pkt_line('bar') 70 | self.assertEqual('bar', self.proto.read_pkt_line()) 71 | self.assertEqual(None, self.proto.read_pkt_line()) 72 | self.proto.unread_pkt_line('baz1') 73 | self.assertRaises(ValueError, self.proto.unread_pkt_line, 'baz2') 74 | 75 | def test_read_pkt_seq(self): 76 | self.rin.write('0008cmd 0005l0000') 77 | self.rin.seek(0) 78 | self.assertEqual(['cmd ', 'l'], list(self.proto.read_pkt_seq())) 79 | 80 | def test_read_pkt_line_none(self): 81 | self.rin.write('0000') 82 | self.rin.seek(0) 83 | self.assertEqual(None, self.proto.read_pkt_line()) 84 | 85 | def test_write_sideband(self): 86 | self.proto.write_sideband(3, 'bloe') 87 | self.assertEqual(self.rout.getvalue(), '0009\x03bloe') 88 | 89 | def test_send_cmd(self): 90 | self.proto.send_cmd('fetch', 'a', 'b') 91 | self.assertEqual(self.rout.getvalue(), '000efetch a\x00b\x00') 92 | 93 | def test_read_cmd(self): 94 | self.rin.write('0012cmd arg1\x00arg2\x00') 95 | self.rin.seek(0) 96 | self.assertEqual(('cmd', ['arg1', 'arg2']), self.proto.read_cmd()) 97 | 98 | def test_read_cmd_noend0(self): 99 | self.rin.write('0011cmd arg1\x00arg2') 100 | self.rin.seek(0) 101 | self.assertRaises(AssertionError, self.proto.read_cmd) 102 | 103 | 104 | class ProtocolTests(BaseProtocolTests, TestCase): 105 | 106 | def setUp(self): 107 | TestCase.setUp(self) 108 | self.rout = StringIO() 109 | self.rin = StringIO() 110 | self.proto = Protocol(self.rin.read, self.rout.write) 111 | 112 | 113 | class ReceivableStringIO(StringIO): 114 | """StringIO with socket-like recv semantics for testing.""" 115 | 116 | def __init__(self): 117 | StringIO.__init__(self) 118 | self.allow_read_past_eof = False 119 | 120 | def recv(self, size): 121 | # fail fast if no bytes are available; in a real socket, this would 122 | # block forever 123 | if self.tell() == len(self.getvalue()) and not self.allow_read_past_eof: 124 | raise AssertionError('Blocking read past end of socket') 125 | if size == 1: 126 | return self.read(1) 127 | # calls shouldn't return quite as much as asked for 128 | return self.read(size - 1) 129 | 130 | 131 | class ReceivableProtocolTests(BaseProtocolTests, TestCase): 132 | 133 | def setUp(self): 134 | TestCase.setUp(self) 135 | self.rout = StringIO() 136 | self.rin = ReceivableStringIO() 137 | self.proto = ReceivableProtocol(self.rin.recv, self.rout.write) 138 | self.proto._rbufsize = 8 139 | 140 | def test_eof(self): 141 | # Allow blocking reads past EOF just for this test. The only parts of 142 | # the protocol that might check for EOF do not depend on the recv() 143 | # semantics anyway. 144 | self.rin.allow_read_past_eof = True 145 | BaseProtocolTests.test_eof(self) 146 | 147 | def test_recv(self): 148 | all_data = '1234567' * 10 # not a multiple of bufsize 149 | self.rin.write(all_data) 150 | self.rin.seek(0) 151 | data = '' 152 | # We ask for 8 bytes each time and actually read 7, so it should take 153 | # exactly 10 iterations. 154 | for _ in xrange(10): 155 | data += self.proto.recv(10) 156 | # any more reads would block 157 | self.assertRaises(AssertionError, self.proto.recv, 10) 158 | self.assertEqual(all_data, data) 159 | 160 | def test_recv_read(self): 161 | all_data = '1234567' # recv exactly in one call 162 | self.rin.write(all_data) 163 | self.rin.seek(0) 164 | self.assertEqual('1234', self.proto.recv(4)) 165 | self.assertEqual('567', self.proto.read(3)) 166 | self.assertRaises(AssertionError, self.proto.recv, 10) 167 | 168 | def test_read_recv(self): 169 | all_data = '12345678abcdefg' 170 | self.rin.write(all_data) 171 | self.rin.seek(0) 172 | self.assertEqual('1234', self.proto.read(4)) 173 | self.assertEqual('5678abc', self.proto.recv(8)) 174 | self.assertEqual('defg', self.proto.read(4)) 175 | self.assertRaises(AssertionError, self.proto.recv, 10) 176 | 177 | def test_mixed(self): 178 | # arbitrary non-repeating string 179 | all_data = ','.join(str(i) for i in xrange(100)) 180 | self.rin.write(all_data) 181 | self.rin.seek(0) 182 | data = '' 183 | 184 | for i in xrange(1, 100): 185 | data += self.proto.recv(i) 186 | # if we get to the end, do a non-blocking read instead of blocking 187 | if len(data) + i > len(all_data): 188 | data += self.proto.recv(i) 189 | # ReceivableStringIO leaves off the last byte unless we ask 190 | # nicely 191 | data += self.proto.recv(1) 192 | break 193 | else: 194 | data += self.proto.read(i) 195 | else: 196 | # didn't break, something must have gone wrong 197 | self.fail() 198 | 199 | self.assertEqual(all_data, data) 200 | 201 | 202 | class CapabilitiesTestCase(TestCase): 203 | 204 | def test_plain(self): 205 | self.assertEqual(('bla', []), extract_capabilities('bla')) 206 | 207 | def test_caps(self): 208 | self.assertEqual(('bla', ['la']), extract_capabilities('bla\0la')) 209 | self.assertEqual(('bla', ['la']), extract_capabilities('bla\0la\n')) 210 | self.assertEqual(('bla', ['la', 'la']), extract_capabilities('bla\0la la')) 211 | 212 | def test_plain_want_line(self): 213 | self.assertEqual(('want bla', []), extract_want_line_capabilities('want bla')) 214 | 215 | def test_caps_want_line(self): 216 | self.assertEqual(('want bla', ['la']), extract_want_line_capabilities('want bla la')) 217 | self.assertEqual(('want bla', ['la']), extract_want_line_capabilities('want bla la\n')) 218 | self.assertEqual(('want bla', ['la', 'la']), extract_want_line_capabilities('want bla la la')) 219 | 220 | def test_ack_type(self): 221 | self.assertEqual(SINGLE_ACK, ack_type(['foo', 'bar'])) 222 | self.assertEqual(MULTI_ACK, ack_type(['foo', 'bar', 'multi_ack'])) 223 | self.assertEqual(MULTI_ACK_DETAILED, 224 | ack_type(['foo', 'bar', 'multi_ack_detailed'])) 225 | # choose detailed when both present 226 | self.assertEqual(MULTI_ACK_DETAILED, 227 | ack_type(['foo', 'bar', 'multi_ack', 228 | 'multi_ack_detailed'])) 229 | 230 | 231 | class BufferedPktLineWriterTests(TestCase): 232 | 233 | def setUp(self): 234 | TestCase.setUp(self) 235 | self._output = StringIO() 236 | self._writer = BufferedPktLineWriter(self._output.write, bufsize=16) 237 | 238 | def assertOutputEquals(self, expected): 239 | self.assertEqual(expected, self._output.getvalue()) 240 | 241 | def _truncate(self): 242 | self._output.seek(0) 243 | self._output.truncate() 244 | 245 | def test_write(self): 246 | self._writer.write('foo') 247 | self.assertOutputEquals('') 248 | self._writer.flush() 249 | self.assertOutputEquals('0007foo') 250 | 251 | def test_write_none(self): 252 | self._writer.write(None) 253 | self.assertOutputEquals('') 254 | self._writer.flush() 255 | self.assertOutputEquals('0000') 256 | 257 | def test_flush_empty(self): 258 | self._writer.flush() 259 | self.assertOutputEquals('') 260 | 261 | def test_write_multiple(self): 262 | self._writer.write('foo') 263 | self._writer.write('bar') 264 | self.assertOutputEquals('') 265 | self._writer.flush() 266 | self.assertOutputEquals('0007foo0007bar') 267 | 268 | def test_write_across_boundary(self): 269 | self._writer.write('foo') 270 | self._writer.write('barbaz') 271 | self.assertOutputEquals('0007foo000abarba') 272 | self._truncate() 273 | self._writer.flush() 274 | self.assertOutputEquals('z') 275 | 276 | def test_write_to_boundary(self): 277 | self._writer.write('foo') 278 | self._writer.write('barba') 279 | self.assertOutputEquals('0007foo0009barba') 280 | self._truncate() 281 | self._writer.write('z') 282 | self._writer.flush() 283 | self.assertOutputEquals('0005z') 284 | 285 | 286 | class PktLineParserTests(TestCase): 287 | 288 | def test_none(self): 289 | pktlines = [] 290 | parser = PktLineParser(pktlines.append) 291 | parser.parse("0000") 292 | self.assertEqual(pktlines, [None]) 293 | self.assertEqual("", parser.get_tail()) 294 | 295 | def test_small_fragments(self): 296 | pktlines = [] 297 | parser = PktLineParser(pktlines.append) 298 | parser.parse("00") 299 | parser.parse("05") 300 | parser.parse("z0000") 301 | self.assertEqual(pktlines, ["z", None]) 302 | self.assertEqual("", parser.get_tail()) 303 | 304 | def test_multiple_packets(self): 305 | pktlines = [] 306 | parser = PktLineParser(pktlines.append) 307 | parser.parse("0005z0006aba") 308 | self.assertEqual(pktlines, ["z", "ab"]) 309 | self.assertEqual("a", parser.get_tail()) 310 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/test_utils.py: -------------------------------------------------------------------------------- 1 | # test_utils.py -- Tests for git test utilities. 2 | # Copyright (C) 2010 Google, Inc. 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | 7 | # as published by the Free Software Foundation; either version 2 8 | # of the License, or (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | """Tests for git test utilities.""" 21 | 22 | from dulwich.object_store import ( 23 | MemoryObjectStore, 24 | ) 25 | from dulwich.objects import ( 26 | Blob, 27 | ) 28 | from dulwich.tests import ( 29 | TestCase, 30 | ) 31 | from utils import ( 32 | make_object, 33 | build_commit_graph, 34 | ) 35 | 36 | 37 | class BuildCommitGraphTest(TestCase): 38 | 39 | def setUp(self): 40 | super(BuildCommitGraphTest, self).setUp() 41 | self.store = MemoryObjectStore() 42 | 43 | def test_linear(self): 44 | c1, c2 = build_commit_graph(self.store, [[1], [2, 1]]) 45 | for obj_id in [c1.id, c2.id, c1.tree, c2.tree]: 46 | self.assertTrue(obj_id in self.store) 47 | self.assertEqual([], c1.parents) 48 | self.assertEqual([c1.id], c2.parents) 49 | self.assertEqual(c1.tree, c2.tree) 50 | self.assertEqual([], list(self.store[c1.tree].iteritems())) 51 | self.assertTrue(c2.commit_time > c1.commit_time) 52 | 53 | def test_merge(self): 54 | c1, c2, c3, c4 = build_commit_graph(self.store, 55 | [[1], [2, 1], [3, 1], [4, 2, 3]]) 56 | self.assertEqual([c2.id, c3.id], c4.parents) 57 | self.assertTrue(c4.commit_time > c2.commit_time) 58 | self.assertTrue(c4.commit_time > c3.commit_time) 59 | 60 | def test_missing_parent(self): 61 | self.assertRaises(ValueError, build_commit_graph, self.store, 62 | [[1], [3, 2], [2, 1]]) 63 | 64 | def test_trees(self): 65 | a1 = make_object(Blob, data='aaa1') 66 | a2 = make_object(Blob, data='aaa2') 67 | c1, c2 = build_commit_graph(self.store, [[1], [2, 1]], 68 | trees={1: [('a', a1)], 69 | 2: [('a', a2, 0100644)]}) 70 | self.assertEqual((0100644, a1.id), self.store[c1.tree]['a']) 71 | self.assertEqual((0100644, a2.id), self.store[c2.tree]['a']) 72 | 73 | def test_attrs(self): 74 | c1, c2 = build_commit_graph(self.store, [[1], [2, 1]], 75 | attrs={1: {'message': 'Hooray!'}}) 76 | self.assertEqual('Hooray!', c1.message) 77 | self.assertEqual('Commit 2', c2.message) 78 | 79 | def test_commit_time(self): 80 | c1, c2, c3 = build_commit_graph(self.store, [[1], [2, 1], [3, 2]], 81 | attrs={1: {'commit_time': 124}, 82 | 2: {'commit_time': 123}}) 83 | self.assertEqual(124, c1.commit_time) 84 | self.assertEqual(123, c2.commit_time) 85 | self.assertTrue(c2.commit_time < c1.commit_time < c3.commit_time) 86 | -------------------------------------------------------------------------------- /Sublime Text/site-packages/dulwich/tests/utils.py: -------------------------------------------------------------------------------- 1 | # utils.py -- Test utilities for Dulwich. 2 | # Copyright (C) 2010 Google, Inc. 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; version 2 7 | # of the License or (at your option) any later version of 8 | # the License. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | # MA 02110-1301, USA. 19 | 20 | """Utility functions common to Dulwich tests.""" 21 | 22 | 23 | import datetime 24 | import os 25 | import shutil 26 | import tempfile 27 | import time 28 | import types 29 | import warnings 30 | 31 | from dulwich.index import ( 32 | commit_tree, 33 | ) 34 | from dulwich.objects import ( 35 | FixedSha, 36 | Commit, 37 | ) 38 | from dulwich.pack import ( 39 | OFS_DELTA, 40 | REF_DELTA, 41 | DELTA_TYPES, 42 | obj_sha, 43 | SHA1Writer, 44 | write_pack_header, 45 | write_pack_object, 46 | create_delta, 47 | ) 48 | from dulwich.repo import Repo 49 | from dulwich.tests import ( 50 | SkipTest, 51 | ) 52 | 53 | # Plain files are very frequently used in tests, so let the mode be very short. 54 | F = 0100644 # Shorthand mode for Files. 55 | 56 | 57 | def open_repo(name): 58 | """Open a copy of a repo in a temporary directory. 59 | 60 | Use this function for accessing repos in dulwich/tests/data/repos to avoid 61 | accidentally or intentionally modifying those repos in place. Use 62 | tear_down_repo to delete any temp files created. 63 | 64 | :param name: The name of the repository, relative to 65 | dulwich/tests/data/repos 66 | :returns: An initialized Repo object that lives in a temporary directory. 67 | """ 68 | temp_dir = tempfile.mkdtemp() 69 | repo_dir = os.path.join(os.path.dirname(__file__), 'data', 'repos', name) 70 | temp_repo_dir = os.path.join(temp_dir, name) 71 | shutil.copytree(repo_dir, temp_repo_dir, symlinks=True) 72 | return Repo(temp_repo_dir) 73 | 74 | 75 | def tear_down_repo(repo): 76 | """Tear down a test repository.""" 77 | temp_dir = os.path.dirname(repo.path.rstrip(os.sep)) 78 | shutil.rmtree(temp_dir) 79 | 80 | 81 | def make_object(cls, **attrs): 82 | """Make an object for testing and assign some members. 83 | 84 | This method creates a new subclass to allow arbitrary attribute 85 | reassignment, which is not otherwise possible with objects having __slots__. 86 | 87 | :param attrs: dict of attributes to set on the new object. 88 | :return: A newly initialized object of type cls. 89 | """ 90 | 91 | class TestObject(cls): 92 | """Class that inherits from the given class, but without __slots__. 93 | 94 | Note that classes with __slots__ can't have arbitrary attributes monkey- 95 | patched in, so this is a class that is exactly the same only with a 96 | __dict__ instead of __slots__. 97 | """ 98 | pass 99 | 100 | obj = TestObject() 101 | for name, value in attrs.iteritems(): 102 | if name == 'id': 103 | # id property is read-only, so we overwrite sha instead. 104 | sha = FixedSha(value) 105 | obj.sha = lambda: sha 106 | else: 107 | setattr(obj, name, value) 108 | return obj 109 | 110 | 111 | def make_commit(**attrs): 112 | """Make a Commit object with a default set of members. 113 | 114 | :param attrs: dict of attributes to overwrite from the default values. 115 | :return: A newly initialized Commit object. 116 | """ 117 | default_time = int(time.mktime(datetime.datetime(2010, 1, 1).timetuple())) 118 | all_attrs = {'author': 'Test Author ', 119 | 'author_time': default_time, 120 | 'author_timezone': 0, 121 | 'committer': 'Test Committer ', 122 | 'commit_time': default_time, 123 | 'commit_timezone': 0, 124 | 'message': 'Test message.', 125 | 'parents': [], 126 | 'tree': '0' * 40} 127 | all_attrs.update(attrs) 128 | return make_object(Commit, **all_attrs) 129 | 130 | 131 | def functest_builder(method, func): 132 | """Generate a test method that tests the given function.""" 133 | 134 | def do_test(self): 135 | method(self, func) 136 | 137 | return do_test 138 | 139 | 140 | def ext_functest_builder(method, func): 141 | """Generate a test method that tests the given extension function. 142 | 143 | This is intended to generate test methods that test both a pure-Python 144 | version and an extension version using common test code. The extension test 145 | will raise SkipTest if the extension is not found. 146 | 147 | Sample usage: 148 | 149 | class MyTest(TestCase); 150 | def _do_some_test(self, func_impl): 151 | self.assertEqual('foo', func_impl()) 152 | 153 | test_foo = functest_builder(_do_some_test, foo_py) 154 | test_foo_extension = ext_functest_builder(_do_some_test, _foo_c) 155 | 156 | :param method: The method to run. It must must two parameters, self and the 157 | function implementation to test. 158 | :param func: The function implementation to pass to method. 159 | """ 160 | 161 | def do_test(self): 162 | if not isinstance(func, types.BuiltinFunctionType): 163 | raise SkipTest("%s extension not found" % func.func_name) 164 | method(self, func) 165 | 166 | return do_test 167 | 168 | 169 | def build_pack(f, objects_spec, store=None): 170 | """Write test pack data from a concise spec. 171 | 172 | :param f: A file-like object to write the pack to. 173 | :param objects_spec: A list of (type_num, obj). For non-delta types, obj 174 | is the string of that object's data. 175 | For delta types, obj is a tuple of (base, data), where: 176 | 177 | * base can be either an index in objects_spec of the base for that 178 | * delta; or for a ref delta, a SHA, in which case the resulting pack 179 | * will be thin and the base will be an external ref. 180 | * data is a string of the full, non-deltified data for that object. 181 | 182 | Note that offsets/refs and deltas are computed within this function. 183 | :param store: An optional ObjectStore for looking up external refs. 184 | :return: A list of tuples in the order specified by objects_spec: 185 | (offset, type num, data, sha, CRC32) 186 | """ 187 | sf = SHA1Writer(f) 188 | num_objects = len(objects_spec) 189 | write_pack_header(sf, num_objects) 190 | 191 | full_objects = {} 192 | offsets = {} 193 | crc32s = {} 194 | 195 | while len(full_objects) < num_objects: 196 | for i, (type_num, data) in enumerate(objects_spec): 197 | if type_num not in DELTA_TYPES: 198 | full_objects[i] = (type_num, data, 199 | obj_sha(type_num, [data])) 200 | continue 201 | base, data = data 202 | if isinstance(base, int): 203 | if base not in full_objects: 204 | continue 205 | base_type_num, _, _ = full_objects[base] 206 | else: 207 | base_type_num, _ = store.get_raw(base) 208 | full_objects[i] = (base_type_num, data, 209 | obj_sha(base_type_num, [data])) 210 | 211 | for i, (type_num, obj) in enumerate(objects_spec): 212 | offset = f.tell() 213 | if type_num == OFS_DELTA: 214 | base_index, data = obj 215 | base = offset - offsets[base_index] 216 | _, base_data, _ = full_objects[base_index] 217 | obj = (base, create_delta(base_data, data)) 218 | elif type_num == REF_DELTA: 219 | base_ref, data = obj 220 | if isinstance(base_ref, int): 221 | _, base_data, base = full_objects[base_ref] 222 | else: 223 | base_type_num, base_data = store.get_raw(base_ref) 224 | base = obj_sha(base_type_num, base_data) 225 | obj = (base, create_delta(base_data, data)) 226 | 227 | crc32 = write_pack_object(sf, type_num, obj) 228 | offsets[i] = offset 229 | crc32s[i] = crc32 230 | 231 | expected = [] 232 | for i in xrange(num_objects): 233 | type_num, data, sha = full_objects[i] 234 | assert len(sha) == 20 235 | expected.append((offsets[i], type_num, data, sha, crc32s[i])) 236 | 237 | sf.write_sha() 238 | f.seek(0) 239 | return expected 240 | 241 | 242 | def build_commit_graph(object_store, commit_spec, trees=None, attrs=None): 243 | """Build a commit graph from a concise specification. 244 | 245 | Sample usage: 246 | >>> c1, c2, c3 = build_commit_graph(store, [[1], [2, 1], [3, 1, 2]]) 247 | >>> store[store[c3].parents[0]] == c1 248 | True 249 | >>> store[store[c3].parents[1]] == c2 250 | True 251 | 252 | If not otherwise specified, commits will refer to the empty tree and have 253 | commit times increasing in the same order as the commit spec. 254 | 255 | :param object_store: An ObjectStore to commit objects to. 256 | :param commit_spec: An iterable of iterables of ints defining the commit 257 | graph. Each entry defines one commit, and entries must be in topological 258 | order. The first element of each entry is a commit number, and the 259 | remaining elements are its parents. The commit numbers are only 260 | meaningful for the call to make_commits; since real commit objects are 261 | created, they will get created with real, opaque SHAs. 262 | :param trees: An optional dict of commit number -> tree spec for building 263 | trees for commits. The tree spec is an iterable of (path, blob, mode) or 264 | (path, blob) entries; if mode is omitted, it defaults to the normal file 265 | mode (0100644). 266 | :param attrs: A dict of commit number -> (dict of attribute -> value) for 267 | assigning additional values to the commits. 268 | :return: The list of commit objects created. 269 | :raise ValueError: If an undefined commit identifier is listed as a parent. 270 | """ 271 | if trees is None: 272 | trees = {} 273 | if attrs is None: 274 | attrs = {} 275 | commit_time = 0 276 | nums = {} 277 | commits = [] 278 | 279 | for commit in commit_spec: 280 | commit_num = commit[0] 281 | try: 282 | parent_ids = [nums[pn] for pn in commit[1:]] 283 | except KeyError, e: 284 | missing_parent, = e.args 285 | raise ValueError('Unknown parent %i' % missing_parent) 286 | 287 | blobs = [] 288 | for entry in trees.get(commit_num, []): 289 | if len(entry) == 2: 290 | path, blob = entry 291 | entry = (path, blob, F) 292 | path, blob, mode = entry 293 | blobs.append((path, blob.id, mode)) 294 | object_store.add_object(blob) 295 | tree_id = commit_tree(object_store, blobs) 296 | 297 | commit_attrs = { 298 | 'message': 'Commit %i' % commit_num, 299 | 'parents': parent_ids, 300 | 'tree': tree_id, 301 | 'commit_time': commit_time, 302 | } 303 | commit_attrs.update(attrs.get(commit_num, {})) 304 | commit_obj = make_commit(**commit_attrs) 305 | 306 | # By default, increment the time by a lot. Out-of-order commits should 307 | # be closer together than this because their main cause is clock skew. 308 | commit_time = commit_attrs['commit_time'] + 100 309 | nums[commit_num] = commit_obj.id 310 | object_store.add_object(commit_obj) 311 | commits.append(commit_obj) 312 | 313 | return commits 314 | 315 | 316 | def setup_warning_catcher(): 317 | """Wrap warnings.showwarning with code that records warnings.""" 318 | 319 | caught_warnings = [] 320 | original_showwarning = warnings.showwarning 321 | 322 | def custom_showwarning(*args, **kwargs): 323 | caught_warnings.append(args[0]) 324 | 325 | warnings.showwarning = custom_showwarning 326 | return caught_warnings 327 | -------------------------------------------------------------------------------- /Visual Studio/Backup/autogit.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "autogit", "autogit\autogit.csproj", "{48468FB5-ECB1-4A7F-91FA-5E68AF365A23}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ganji.Repo", "Ganji.Repo\Ganji.Repo.csproj", "{34FEC610-707E-4C7A-A529-52958FB7261D}" 7 | EndProject 8 | Global 9 | GlobalSection(CodealikeProperties) = postSolution 10 | SolutionGuid = d4f1158c-586c-4f06-94b7-2012577d206b 11 | EndGlobalSection 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Any CPU = Debug|Any CPU 14 | Release|Any CPU = Release|Any CPU 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23}.Release|Any CPU.Build.0 = Release|Any CPU 21 | {34FEC610-707E-4C7A-A529-52958FB7261D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {34FEC610-707E-4C7A-A529-52958FB7261D}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {34FEC610-707E-4C7A-A529-52958FB7261D}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {34FEC610-707E-4C7A-A529-52958FB7261D}.Release|Any CPU.Build.0 = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /Visual Studio/Ganji.Repo/Ganji.Repo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {34FEC610-707E-4C7A-A529-52958FB7261D} 9 | Library 10 | Properties 11 | Ganji.Repo 12 | Ganji.Repo 13 | v4.0 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | true 38 | 39 | 40 | Key.snk 41 | 42 | 43 | 44 | False 45 | ..\packages\LibGit2Sharp.0.13.0.0\lib\net35\LibGit2Sharp.dll 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /Visual Studio/Ganji.Repo/GitProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | using NGit; 7 | using NGit.Treewalk; 8 | using NGit.Revwalk; 9 | using NGit.Dircache; 10 | using NGit.Treewalk.Filter; 11 | 12 | namespace Ganji.Repo 13 | { 14 | [Obsolete] 15 | class GitProvider 16 | { 17 | public string SolutionBaseDirectory 18 | { 19 | get; 20 | set; 21 | } 22 | public string ContextRepository 23 | { 24 | get; 25 | set; 26 | } 27 | 28 | NGit.Api.Git m_git; 29 | public void Init(string path) 30 | { 31 | NGit.Api.InitCommand init = new NGit.Api.InitCommand(); 32 | 33 | System.IO.Directory.CreateDirectory(path); 34 | 35 | System.IO.Directory.CreateDirectory(System.IO.Path.Combine(path, "saves")); 36 | System.IO.Directory.CreateDirectory(System.IO.Path.Combine(path, "builds")); 37 | System.IO.Directory.CreateDirectory(System.IO.Path.Combine(path, "days")); 38 | init.SetDirectory(new Sharpen.FilePath(path)); 39 | m_git = init.Call(); 40 | } 41 | 42 | public string ReadCommit(string commitId, string fileName) 43 | { 44 | var repo = m_git.GetRepository(); 45 | var id = ObjectId.FromString(commitId); 46 | 47 | RevCommit commit = null; 48 | try 49 | { 50 | commit = ParseCommit(repo, id); 51 | if (commit == null) 52 | return null; 53 | } 54 | catch (Exception ex) 55 | { 56 | Trace.WriteLine(ex.Message); 57 | return null; 58 | } 59 | //var commits = m_git.Log().AddRange(id, id).Call(); 60 | //var commit = commits.SingleOrDefault(); 61 | //if (commit == null) 62 | // return null; 63 | 64 | TreeWalk walk = new TreeWalk(repo); 65 | //RevWalk r = new RevWalk(m_git.GetRepository()); 66 | //var tree = r.ParseTree(commit.Tree.Id); 67 | //r.LookupTree( 68 | //walk.AddTree(new FileTreeIterator(repo)); 69 | 70 | //var tree = ParseTree(repo, commit.Tree.Id); 71 | walk.AddTree(commit.Tree); 72 | var filter = GetGitFriendlyName(fileName); 73 | walk.Filter = PathFilterGroup.CreateFromStrings(new string[]{filter}); 74 | //walk.EnterSubtree(); 75 | while (walk.Next()) 76 | { 77 | var path = walk.PathString; 78 | if (walk.IsSubtree) 79 | { 80 | walk.EnterSubtree(); 81 | continue; 82 | } 83 | if (path == filter) 84 | { 85 | var cur = walk.GetObjectId(0); 86 | ObjectLoader ol = repo.Open(cur); 87 | 88 | // //Console.WriteLine(string.Format("Path: {0}{1}", walk.PathString, walk.IsSubtree ? "/" : "")); 89 | // //var loader = reader.Open(commit.Tree.Id); 90 | var text = ""; 91 | using (var stream = ol.OpenStream()) 92 | using (var sr = new System.IO.StreamReader(stream)) 93 | { 94 | text = sr.ReadToEnd(); 95 | } 96 | return text; 97 | } 98 | } 99 | //walk.Reset(); 100 | //reader.Open(); 101 | return ""; 102 | } 103 | 104 | private RevCommit ParseCommit(Repository repo, ObjectId id) 105 | { 106 | RevWalk rw = new RevWalk(repo); 107 | var head = rw.ParseCommit(id); 108 | rw.MarkStart(head); 109 | RevCommit commit = null; 110 | try 111 | { 112 | commit = rw.Next(); 113 | while( commit != null ) 114 | { 115 | if (commit.Id.Name == id.Name) 116 | { 117 | return commit; 118 | } 119 | commit = rw.Next(); 120 | } 121 | 122 | } 123 | finally 124 | { 125 | rw.Release(); 126 | } 127 | return commit; 128 | } 129 | 130 | private RevTree ParseTree(Repository repo, ObjectId id) 131 | { 132 | RevWalk rw = new RevWalk(repo); 133 | 134 | RevTree tree; 135 | try 136 | { 137 | tree = rw.LookupTree(id); 138 | } 139 | finally 140 | { 141 | rw.Release(); 142 | } 143 | return tree; 144 | } 145 | 146 | 147 | public void Open(string path) 148 | { 149 | var p = new Sharpen.FilePath(path); 150 | try 151 | { 152 | m_git = NGit.Api.Git.Open(p); 153 | } 154 | catch (Exception ex) 155 | { 156 | } 157 | if (m_git == null) 158 | { 159 | Init(path); 160 | } 161 | 162 | } 163 | 164 | public string Commit() 165 | { 166 | if (m_git == null) 167 | throw new ArgumentException(); 168 | 169 | try 170 | { 171 | var rev = m_git.Commit().SetMessage("Ganji autocommit").Call(); 172 | return rev.Id.Name; 173 | } 174 | catch (Exception ex) 175 | { 176 | Trace.WriteLine(ex.Message); 177 | } 178 | return ""; 179 | } 180 | 181 | private string GetRelativeName(string file) 182 | { 183 | var dir = SolutionBaseDirectory.EndsWith("\\") ? SolutionBaseDirectory : SolutionBaseDirectory + "\\"; 184 | return file.Replace(dir, ""); 185 | } 186 | 187 | private string GetGitFriendlyName(string file) 188 | { 189 | var relative = GetRelativeName(file); 190 | var parts = relative.Split(System.IO.Path.DirectorySeparatorChar); 191 | return string.Join("/", parts); 192 | } 193 | 194 | public void CopyFileToCache(string file) 195 | { 196 | try 197 | { 198 | var newPath = PrepareDocumentCache(file, ContextRepository); 199 | System.IO.File.Copy(file, newPath, true); 200 | //m_git.Add().AddFilepattern(tuple.Item1).Call(); 201 | //m_git.Add().AddFilepattern(".").Call(); 202 | 203 | var command = m_git.Add(); 204 | var filter = GetGitFriendlyName(file); 205 | 206 | command.AddFilepattern(filter).Call(); 207 | } 208 | catch (Exception ex) 209 | { 210 | Trace.WriteLine(ex.Message); 211 | } 212 | } 213 | 214 | private string PrepareDocumentCache(string file, string repoPath) 215 | { 216 | string relativePath = GetRelativeName(file); 217 | var newPath = System.IO.Path.Combine(repoPath, relativePath ); 218 | var dirPath = System.IO.Path.GetDirectoryName(newPath); 219 | if (!System.IO.File.Exists(dirPath)) 220 | { 221 | // This will create subdirectories too if missing... 222 | System.IO.Directory.CreateDirectory(dirPath); 223 | } 224 | return newPath; 225 | } 226 | 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /Visual Studio/Ganji.Repo/GitProviderLibGit2Sharp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using LibGit2Sharp; 6 | using System.Security.Principal; 7 | using System.Reflection; 8 | using System.IO; 9 | using System.Diagnostics; 10 | 11 | namespace Ganji.Repo 12 | { 13 | // Generate a private/public key 14 | // http://www.codeguru.com/csharp/.net/net_general/article.php/c4643/Giving-a-NET-Assembly-a-Strong-Name.htm 15 | 16 | // Sign LibGit2Sharp 17 | // http://stackoverflow.com/questions/1379954/how-i-do-a-sign-an-assembly-that-has-already-been-built-into-a-dll-specifically 18 | /* 19 | From a VS.NET command prompt, enter the following: 20 | 21 | Generate a KeyFile: sn -k keyPair.snk 22 | Obtain the MSIL for the provided assembly: ildasm providedAssembly.dll /out:providedAssembly.il 23 | Rename/move the original assembly: ren providedAssembly.dll providedAssembly.dll.orig 24 | Create a new assembly from the MSIL output and your assembly KeyFile: ilasm providedAssembly.il /dll /key= keyPair.snk 25 | */ 26 | 27 | public class GitProviderLibGit2Sharp 28 | { 29 | public string SolutionBaseDirectory 30 | { 31 | get; 32 | set; 33 | } 34 | public string ContextRepository 35 | { 36 | get; 37 | set; 38 | } 39 | // Good sample 40 | // https://github.com/libgit2/libgit2sharp/blob/master/LibGit2Sharp.Tests/CommitFixture.cs 41 | 42 | private void SetEnvironmentPath() 43 | { 44 | string originalAssemblypath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath; 45 | 46 | //TODO: When amd64 version of libgit2.dll is available, value this depending of the size of an IntPtr 47 | //const string currentArchSubPath = "/x86"; 48 | 49 | string path = Path.Combine(Path.GetDirectoryName(originalAssemblypath), "NativeBinaries", "x86"); 50 | 51 | const string pathEnvVariable = "PATH"; 52 | Environment.SetEnvironmentVariable(pathEnvVariable, 53 | String.Format("{0}{1}{2}", path, Path.PathSeparator, Environment.GetEnvironmentVariable(pathEnvVariable))); 54 | } 55 | 56 | public void Init(string path) 57 | { 58 | System.IO.Directory.CreateDirectory(path); 59 | 60 | try 61 | { 62 | //Assembly.LoadFile(@"\\psf\Home\Desktop\repo\code\trunk\Ganji\Ganji.Repo.Tests\bin\Debug\LibGit2Sharp.dll"); 63 | //SetEnvironmentPath(); 64 | 65 | Repository.Init(path, false); 66 | { 67 | //System.IO.Directory.CreateDirectory(System.IO.Path.Combine(path, "saves")); 68 | //System.IO.Directory.CreateDirectory(System.IO.Path.Combine(path, "builds")); 69 | //System.IO.Directory.CreateDirectory(System.IO.Path.Combine(path, "days")); 70 | } 71 | } 72 | catch( Exception ex ) 73 | { 74 | if (ex.InnerException != null 75 | && ex.InnerException.Message.StartsWith( "Unable to load DLL 'git2':")) 76 | { 77 | throw new Exception( 78 | @""" 79 | When referencing Ganji.Repo, you must also add the following PostBuild Step to the referencing project: 80 | 81 | if not exist ""$(TargetDir)NativeBinaries"" md ""$(TargetDir)NativeBinaries"" 82 | if not exist ""$(TargetDir)NativeBinaries\x86"" md ""$(TargetDir)NativeBinaries\x86"" 83 | xcopy /s /y ""$(SolutionDir)packages\LibGit2Sharp.0.8\NativeBinaries\x86\*.*"" ""$(TargetDir)NativeBinaries\x86"" 84 | if not exist ""$(TargetDir)NativeBinaries\amd64"" md ""$(TargetDir)NativeBinaries\amd64"" 85 | xcopy /s /y ""$(SolutionDir)packages\LibGit2Sharp.0.8\NativeBinaries\amd64\*.*"" ""$(TargetDir)NativeBinaries\amd64"" 86 | 87 | Alternatively, 88 | 89 | Select the Project Reference node to 'Ganji.Repo' in Solution Explorer and view the Properties (F4) 90 | Change the value for ""Output Groups Included in VSIX"" to the following: BuiltProjectOutputGroup;BuiltProjectOutputGroupDependencies;GetCopyToOutputDirectoryItems;SatelliteDllsProjectOutputGroup 91 | 92 | http://stackoverflow.com/questions/6974244/vsix-package-doesnt-include-localized-resources-of-referenced-assembly 93 | """ 94 | ); 95 | } 96 | } 97 | } 98 | 99 | string RepoPath; 100 | string UserName; 101 | public void Open(string path) 102 | { 103 | this.RepoPath = path; 104 | this.ContextRepository = RepoPath; 105 | this.UserName = WindowsIdentity.GetCurrent().Name; 106 | } 107 | 108 | public bool CopyFileToCache(string file, string projectPath) 109 | { 110 | using (Repository repo = new Repository(RepoPath)) 111 | { 112 | var newPath = PrepareDocumentCache(file, ContextRepository, projectPath); 113 | System.IO.File.Copy(file, newPath, true); 114 | 115 | repo.Index.Stage(newPath); 116 | 117 | // TODO handle deleted files. 118 | var status = repo.Index.RetrieveStatus(newPath); 119 | if (status == FileStatus.Unaltered) 120 | { 121 | // file was unchanged...can skip commit. 122 | return false; 123 | } 124 | return true; 125 | 126 | } 127 | } 128 | 129 | public string Commit(string kind) 130 | { 131 | if( string.IsNullOrEmpty( RepoPath ) ) 132 | throw new ArgumentException("Must open first"); 133 | 134 | using( Repository repo = new Repository(RepoPath) ) 135 | { 136 | var author = new Signature(UserName, UserName, DateTimeOffset.Now); 137 | var commit = repo.Commit( string.Format("Ganji commit - {0}", kind), author, author); 138 | return commit.Id.Sha; 139 | } 140 | } 141 | 142 | //public string ReadCommit(string commitId, string fileName) 143 | //{ 144 | // try 145 | // { 146 | // string relativePath = GetRelativeName(fileName); 147 | // using (Repository repo = new Repository(RepoPath)) 148 | // { 149 | // var commit = repo.Lookup(commitId); 150 | // if (commit == null) 151 | // return null; 152 | // var blob = commit[relativePath]; 153 | // if( blob == null ) 154 | // return null; 155 | // var blobTarget = blob.Target as Blob; 156 | // return blobTarget.ContentAsUtf8(); 157 | // } 158 | // } 159 | // catch (Exception ex) 160 | // { 161 | // Trace.WriteLine(ex.Message); 162 | // } 163 | // return null; 164 | //} 165 | 166 | private string PrepareDocumentCache(string file, string repoPath, string projectPath) 167 | { 168 | string relativePath = GetRelativeName(file, projectPath); 169 | var newPath = System.IO.Path.Combine(repoPath, relativePath); 170 | var dirPath = System.IO.Path.GetDirectoryName(newPath); 171 | if (!System.IO.File.Exists(dirPath)) 172 | { 173 | // This will create subdirectories too if missing... 174 | System.IO.Directory.CreateDirectory(dirPath); 175 | } 176 | return newPath; 177 | } 178 | 179 | //private string GetGitFriendlyName(string file) 180 | //{ 181 | // var relative = GetRelativeName(file); 182 | // var parts = relative.Split(System.IO.Path.DirectorySeparatorChar); 183 | // return string.Join("/", parts); 184 | //} 185 | 186 | private string GetRelativeName(string file, string projectPath) 187 | { 188 | // Test if project is in NOT solution directory 189 | if (SolutionBaseDirectory.Replace(projectPath, "").Length == SolutionBaseDirectory.Length) 190 | { 191 | // Then lets use project to calc relative path. 192 | var dir = projectPath.EndsWith("\\") ? projectPath : projectPath + "\\"; 193 | return file.Replace(dir, ""); 194 | } 195 | else 196 | { 197 | var dir = SolutionBaseDirectory.EndsWith("\\") ? SolutionBaseDirectory : SolutionBaseDirectory + "\\"; 198 | return file.Replace(dir, ""); 199 | } 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /Visual Studio/Ganji.Repo/Key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/Ganji.Repo/Key.snk -------------------------------------------------------------------------------- /Visual Studio/Ganji.Repo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Ganji.Repo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Ganji.Repo")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("65f30d2c-6fd8-4280-b933-f6c6f7a1ca67")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Visual Studio/Ganji.Repo/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Visual Studio/autogit.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30723.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "autogit", "autogit\autogit.csproj", "{48468FB5-ECB1-4A7F-91FA-5E68AF365A23}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ganji.Repo", "Ganji.Repo\Ganji.Repo.csproj", "{34FEC610-707E-4C7A-A529-52958FB7261D}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {34FEC610-707E-4C7A-A529-52958FB7261D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {34FEC610-707E-4C7A-A529-52958FB7261D}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {34FEC610-707E-4C7A-A529-52958FB7261D}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {34FEC610-707E-4C7A-A529-52958FB7261D}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(CodealikeProperties) = postSolution 29 | SolutionGuid = d4f1158c-586c-4f06-94b7-2012577d206b 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Visual Studio/autogit/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. Project-level 3 | // suppressions either have no target or are given a specific target 4 | // and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Error List, point to "Suppress Message(s)", and click "In Project 8 | // Suppression File". You do not need to add suppressions to this 9 | // file manually. 10 | 11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")] 12 | -------------------------------------------------------------------------------- /Visual Studio/autogit/Guids.cs: -------------------------------------------------------------------------------- 1 | // Guids.cs 2 | // MUST match guids.h 3 | using System; 4 | 5 | namespace ninlabsresearch.autogit 6 | { 7 | static class GuidList 8 | { 9 | public const string guidautogitPkgString = "c567cea0-d935-42b4-8ae0-31a019f6a071"; 10 | public const string guidautogitCmdSetString = "7e2e501b-d891-4cab-a411-686d41e9c27b"; 11 | 12 | public static readonly Guid guidautogitCmdSet = new Guid(guidautogitCmdSetString); 13 | }; 14 | } -------------------------------------------------------------------------------- /Visual Studio/autogit/Key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/autogit/Key.snk -------------------------------------------------------------------------------- /Visual Studio/autogit/PkgCmdID.cs: -------------------------------------------------------------------------------- 1 | // PkgCmdID.cs 2 | // MUST match PkgCmdID.h 3 | using System; 4 | 5 | namespace ninlabsresearch.autogit 6 | { 7 | static class PkgCmdIDList 8 | { 9 | public const uint autogitOptionsCommand = 0x100; 10 | 11 | 12 | }; 13 | } -------------------------------------------------------------------------------- /Visual Studio/autogit/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("autogit")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("ninlabs research")] 14 | [assembly: AssemblyProduct("autogit")] 15 | [assembly: AssemblyCopyright("")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | [assembly: ComVisible(false)] 19 | [assembly: CLSCompliant(false)] 20 | [assembly: NeutralResourcesLanguage("en-US")] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Revision and Build Numbers 30 | // by using the '*' as shown below: 31 | 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Visual Studio/autogit/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.34014 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ninlabsresearch.autogit { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ninlabsresearch.autogit.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Visual Studio/autogit/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 11 | 12 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | text/microsoft-resx 119 | 120 | 121 | 2.0 122 | 123 | 124 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 125 | 126 | 127 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 128 | 129 | -------------------------------------------------------------------------------- /Visual Studio/autogit/Resources/Images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/autogit/Resources/Images.png -------------------------------------------------------------------------------- /Visual Studio/autogit/Resources/Package.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/autogit/Resources/Package.ico -------------------------------------------------------------------------------- /Visual Studio/autogit/SaveListener.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Microsoft.VisualStudio.Shell.Interop; 6 | using Microsoft.VisualStudio; 7 | using Microsoft.VisualStudio.Shell; 8 | using Ganji.Repo; 9 | using System.Diagnostics; 10 | using System.Globalization; 11 | using EnvDTE; 12 | using System.IO; 13 | 14 | namespace ninlabsresearch.autogit 15 | { 16 | class SaveListener : IVsRunningDocTableEvents3 17 | { 18 | GitProviderLibGit2Sharp provider; 19 | IVsRunningDocumentTable m_RDT; 20 | uint m_rdtCookie = 0; 21 | public bool Register(EnvDTE.DTE dte, string repoPath, string solutionPath) 22 | { 23 | // Register events for running document table. 24 | m_RDT = (IVsRunningDocumentTable)Package.GetGlobalService(typeof(SVsRunningDocumentTable)); 25 | m_RDT.AdviseRunningDocTableEvents(this, out m_rdtCookie); 26 | 27 | provider = new GitProviderLibGit2Sharp(); 28 | provider.ContextRepository = repoPath; 29 | provider.SolutionBaseDirectory = solutionPath; 30 | provider.Open(repoPath); 31 | 32 | // I: test if this table is from multiple instances routed here... 33 | return true; 34 | } 35 | 36 | public void Shutdown() 37 | { 38 | if (m_RDT != null) 39 | { 40 | m_RDT.UnadviseRunningDocTableEvents(m_rdtCookie); 41 | m_RDT = null; 42 | } 43 | } 44 | 45 | // IVsRunningDocTableEvents3 Members 46 | public int OnAfterAttributeChange(uint docCookie, uint grfAttribs) 47 | { 48 | return VSConstants.S_OK; 49 | } 50 | 51 | // renames... 52 | public int OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, IVsHierarchy pHierOld, uint itemidOld, string pszMkDocumentOld, IVsHierarchy pHierNew, uint itemidNew, string pszMkDocumentNew) 53 | { 54 | //// look up pszMkDocumentOld 55 | //// update record to be with pszMkDocumentNew 56 | //if (pszMkDocumentOld != pszMkDocumentNew) 57 | //{ 58 | // m_docContext.UpdateRenamedDocument(pszMkDocumentOld, pszMkDocumentNew, m_database); 59 | //} 60 | return VSConstants.S_OK; 61 | } 62 | 63 | public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) 64 | { 65 | return VSConstants.S_OK; 66 | } 67 | 68 | public int OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) 69 | { 70 | return VSConstants.S_OK; 71 | } 72 | 73 | Dictionary saveTimes = new Dictionary(); 74 | public int OnBeforeSave(uint docCookie) 75 | { 76 | uint flags, readlocks, editlocks; 77 | string name; IVsHierarchy hier; 78 | uint itemid; IntPtr docData; 79 | m_RDT.GetDocumentInfo(docCookie, out flags, out readlocks, out editlocks, out name, out hier, out itemid, out docData); 80 | 81 | string projectPath = ""; 82 | try 83 | { 84 | var project = GetProject(hier); 85 | if (project != null) 86 | { 87 | // Set so rel path will be C:\path\SolutionDir\ProjectDir\project.csproj => ProjectDir\ 88 | projectPath = Path.GetDirectoryName(Path.GetDirectoryName(project.FullName)); 89 | } 90 | } 91 | catch (Exception ex) 92 | { 93 | 94 | } 95 | 96 | HandleSave(name, "pre save", projectPath); 97 | 98 | return VSConstants.S_OK; 99 | } 100 | 101 | public int OnAfterSave(uint docCookie) 102 | { 103 | uint flags, readlocks, editlocks; 104 | string name; IVsHierarchy hier; 105 | uint itemid; IntPtr docData; 106 | m_RDT.GetDocumentInfo(docCookie, out flags, out readlocks, out editlocks, out name, out hier, out itemid, out docData); 107 | 108 | string projectPath = ""; 109 | try 110 | { 111 | var project = GetProject(hier); 112 | if (project != null) 113 | { 114 | // Set so rel path will be C:\path\SolutionDir\ProjectDir\project.csproj => ProjectDir\ 115 | projectPath = Path.GetDirectoryName( Path.GetDirectoryName( project.FullName ) ); 116 | } 117 | } 118 | catch (Exception ex) 119 | { 120 | 121 | } 122 | 123 | HandleSave(name, "post save", projectPath); 124 | return VSConstants.S_OK; 125 | } 126 | 127 | private void HandleSave(string name, string kind, string projectPath) 128 | { 129 | try 130 | { 131 | // add file to commit! 132 | if (provider.CopyFileToCache(name, projectPath)) 133 | { 134 | // commit to git... 135 | var commitId = provider.Commit(kind); 136 | } 137 | } 138 | catch (Exception ex) 139 | { 140 | Console.WriteLine(ex.Message); 141 | IVsActivityLog log = autogitPackage.GetGlobalService(typeof(SVsActivityLog)) as IVsActivityLog; 142 | if (log == null) return; 143 | 144 | int hr = log.LogEntry((UInt32)__ACTIVITYLOG_ENTRYTYPE.ALE_ERROR, 145 | this.ToString(), ex.Message +":"+ name + ":" + kind); 146 | } 147 | 148 | } 149 | 150 | public Project GetProject(IVsHierarchy hierarchy) 151 | { 152 | object project; 153 | 154 | ErrorHandler.ThrowOnFailure 155 | (hierarchy.GetProperty( 156 | VSConstants.VSITEMID_ROOT, 157 | (int)__VSHPROPID.VSHPROPID_ExtObject, 158 | out project)); 159 | 160 | return (project as Project); 161 | } 162 | 163 | public IVsHierarchy GetHierarchy(IServiceProvider serviceProvider, Project project) 164 | { 165 | var solution = 166 | serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution; 167 | 168 | IVsHierarchy hierarchy; 169 | 170 | solution.GetProjectOfUniqueName(project.FullName, out hierarchy); 171 | 172 | return hierarchy; 173 | } 174 | 175 | public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) 176 | { 177 | return VSConstants.S_OK; 178 | } 179 | 180 | public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) 181 | { 182 | return VSConstants.S_OK; 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /Visual Studio/autogit/VSPackage.resx: -------------------------------------------------------------------------------- 1 |  2 | 12 | 13 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | text/microsoft-resx 120 | 121 | 122 | 2.0 123 | 124 | 125 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 126 | 127 | 128 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 129 | 130 | 131 | 132 | autogit 133 | 134 | 135 | Auto commit code changes to git. 136 | 137 | 138 | Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 139 | 140 | -------------------------------------------------------------------------------- /Visual Studio/autogit/autogit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 12.0 5 | 11.0 6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 7 | 8 | 9 | 10 | 11 | 12 | 4.0 13 | publish\ 14 | true 15 | Disk 16 | false 17 | Foreground 18 | 7 19 | Days 20 | false 21 | false 22 | true 23 | 0 24 | 1.0.0.%2a 25 | false 26 | false 27 | true 28 | 29 | 30 | 31 | Debug 32 | AnyCPU 33 | 2.0 34 | {48468FB5-ECB1-4A7F-91FA-5E68AF365A23} 35 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 36 | Library 37 | Properties 38 | ninlabsresearch.autogit 39 | autogit 40 | True 41 | Key.snk 42 | v4.0 43 | 44 | 45 | true 46 | full 47 | false 48 | bin\Debug\ 49 | DEBUG;TRACE 50 | prompt 51 | 4 52 | 53 | 54 | pdbonly 55 | true 56 | bin\Release\ 57 | TRACE 58 | prompt 59 | 4 60 | true 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | true 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | {80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2} 87 | 8 88 | 0 89 | 0 90 | primary 91 | False 92 | False 93 | 94 | 95 | {26AD1324-4B7C-44BC-84F8-B86AED45729F} 96 | 10 97 | 0 98 | 0 99 | primary 100 | False 101 | False 102 | 103 | 104 | {1A31287A-4D7D-413E-8E32-3B374931BD89} 105 | 8 106 | 0 107 | 0 108 | primary 109 | False 110 | False 111 | 112 | 113 | {2CE2370E-D744-4936-A090-3FFFE667B0E1} 114 | 9 115 | 0 116 | 0 117 | primary 118 | False 119 | False 120 | 121 | 122 | {1CBA492E-7263-47BB-87FE-639000619B15} 123 | 8 124 | 0 125 | 0 126 | primary 127 | False 128 | False 129 | 130 | 131 | {00020430-0000-0000-C000-000000000046} 132 | 2 133 | 0 134 | 0 135 | primary 136 | False 137 | False 138 | 139 | 140 | 141 | 142 | 143 | True 144 | True 145 | Resources.resx 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | ResXFileCodeGenerator 156 | Resources.Designer.cs 157 | Designer 158 | 159 | 160 | true 161 | VSPackage 162 | 163 | 164 | 165 | 166 | true 167 | 168 | 169 | Designer 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | Menus.ctmenu 178 | Designer 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | {34fec610-707e-4c7a-a529-52958fb7261d} 190 | Ganji.Repo 191 | 192 | 193 | 194 | true 195 | 196 | 197 | 198 | $(MSBuildProjectDirectory)\..\packages\LibGit2Sharp.0.13.0.0\NativeBinaries 199 | 200 | 201 | 202 | NativeBinaries\%(RecursiveDir)%(Filename)%(Extension) 203 | PreserveNewest 204 | true 205 | 206 | 207 | 208 | 209 | False 210 | Microsoft .NET Framework 4 %28x86 and x64%29 211 | true 212 | 213 | 214 | False 215 | .NET Framework 3.5 SP1 Client Profile 216 | false 217 | 218 | 219 | False 220 | .NET Framework 3.5 SP1 221 | false 222 | 223 | 224 | False 225 | Windows Installer 4.5 226 | true 227 | 228 | 229 | 230 | 231 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /Visual Studio/autogit/autogit.vsct: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 55 | 76 | 77 | 78 | 79 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /Visual Studio/autogit/autogitPackage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.Runtime.InteropServices; 5 | using System.ComponentModel.Design; 6 | using Microsoft.Win32; 7 | using Microsoft.VisualStudio; 8 | using Microsoft.VisualStudio.Shell.Interop; 9 | using Microsoft.VisualStudio.OLE.Interop; 10 | using Microsoft.VisualStudio.Shell; 11 | using Ganji.Repo; 12 | 13 | namespace ninlabsresearch.autogit 14 | { 15 | /// 16 | /// This is the class that implements the package exposed by this assembly. 17 | /// 18 | /// The minimum requirement for a class to be considered a valid package for Visual Studio 19 | /// is to implement the IVsPackage interface and register itself with the shell. 20 | /// This package uses the helper classes defined inside the Managed Package Framework (MPF) 21 | /// to do it: it derives from the Package class that provides the implementation of the 22 | /// IVsPackage interface and uses the registration attributes defined in the framework to 23 | /// register itself and its components with the shell. 24 | /// 25 | // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is 26 | // a package. 27 | [PackageRegistration(UseManagedResourcesOnly = true)] 28 | // This attribute is used to register the information needed to show this package 29 | // in the Help/About dialog of Visual Studio. 30 | [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] 31 | // This attribute is needed to let the shell know that this package exposes some menus. 32 | [ProvideMenuResource("Menus.ctmenu", 1)] 33 | [Guid(GuidList.guidautogitPkgString)] 34 | // VSContants.UICONTEXT_SolutionExists 35 | [ProvideAutoLoad("f1536ef8-92ec-443c-9ed7-fdadf150da82")] 36 | //[ProvideAutoLoad(VSConstants.UICONTEXT.NoSolution_string)] 37 | public sealed class autogitPackage : Package, IVsSolutionEvents 38 | { 39 | private uint m_solutionCookie = 0; 40 | public EnvDTE.DTE m_dte { get; set; } 41 | 42 | SaveListener m_saveListener; 43 | 44 | public autogitPackage() 45 | { 46 | Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString())); 47 | } 48 | 49 | /// 50 | /// Initialization of the package; this method is called right after the package is sited, so this is the place 51 | /// where you can put all the initialization code that rely on services provided by VisualStudio. 52 | /// 53 | protected override void Initialize() 54 | { 55 | Debug.WriteLine (string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString())); 56 | base.Initialize(); 57 | 58 | // Add our command handlers for menu (commands must exist in the .vsct file) 59 | //OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; 60 | //if ( null != mcs ) 61 | //{ 62 | // // Create the command for the menu item. 63 | // CommandID menuCommandID = new CommandID(GuidList.guidautogitCmdSet, (int)PkgCmdIDList.autogitOptionsCommand); 64 | // MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID ); 65 | // mcs.AddCommand( menuItem ); 66 | //} 67 | 68 | IVsSolution solution = (IVsSolution)GetService(typeof(SVsSolution)); 69 | ErrorHandler.ThrowOnFailure(solution.AdviseSolutionEvents(this, out m_solutionCookie)); 70 | } 71 | 72 | /// 73 | /// This function is the callback used to execute a command when the a menu item is clicked. 74 | /// See the Initialize method to see how the menu item is associated to this function using 75 | /// the OleMenuCommandService service and the MenuCommand class. 76 | /// 77 | private void MenuItemCallback(object sender, EventArgs e) 78 | { 79 | // Show a Message Box to prove we were here 80 | IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell)); 81 | Guid clsid = Guid.Empty; 82 | int result; 83 | Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox( 84 | 0, 85 | ref clsid, 86 | "autogit", 87 | string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.ToString()), 88 | string.Empty, 89 | 0, 90 | OLEMSGBUTTON.OLEMSGBUTTON_OK, 91 | OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, 92 | OLEMSGICON.OLEMSGICON_INFO, 93 | 0, // false 94 | out result)); 95 | } 96 | 97 | 98 | #region IVsSolutionEvents Members 99 | 100 | public int OnAfterCloseSolution(object pUnkReserved) 101 | { 102 | return VSConstants.S_OK; 103 | } 104 | 105 | public int OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy) 106 | { 107 | return VSConstants.S_OK; 108 | } 109 | 110 | public int OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded) 111 | { 112 | return VSConstants.S_OK; 113 | } 114 | 115 | public int OnAfterOpenSolution(object pUnkReserved, int fNewSolution) 116 | { 117 | InitializeWithDTEAndSolutionReady(); 118 | return VSConstants.S_OK; 119 | } 120 | 121 | private void InitializeWithDTEAndSolutionReady() 122 | { 123 | m_dte = (EnvDTE.DTE)this.GetService(typeof(EnvDTE.DTE)); 124 | 125 | if (m_dte == null) 126 | ErrorHandler.ThrowOnFailure(1); 127 | 128 | var solutionBase = ""; 129 | var solutionName = ""; 130 | if (m_dte.Solution != null) 131 | { 132 | solutionBase = System.IO.Path.GetDirectoryName(m_dte.Solution.FullName); 133 | solutionName = System.IO.Path.GetFileNameWithoutExtension(m_dte.Solution.FullName); 134 | } 135 | //string dbName = string.Format("Ganji.History-{0}.sdf", solutionName); 136 | 137 | var basePath = PreparePath(); 138 | var repositoryPath = System.IO.Path.Combine(basePath, "LocalHistory"); 139 | var solutionPath = solutionBase; 140 | 141 | m_saveListener = new SaveListener(); 142 | m_saveListener.Register(m_dte, repositoryPath, solutionPath); 143 | } 144 | 145 | private string PreparePath() 146 | { 147 | var basePath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments); 148 | if (m_dte.Solution != null) 149 | { 150 | basePath = System.IO.Path.GetDirectoryName(m_dte.Solution.FullName); 151 | } 152 | basePath = System.IO.Path.Combine(basePath, ".HistoryData"); 153 | if (!System.IO.Directory.Exists(basePath)) 154 | { 155 | var info = System.IO.Directory.CreateDirectory(basePath); 156 | info.Attributes |= System.IO.FileAttributes.Hidden; 157 | } 158 | 159 | // Also prepare save/build data 160 | var contextPath = System.IO.Path.Combine(basePath, "LocalHistory"); 161 | 162 | if (!System.IO.Directory.Exists(contextPath)) 163 | { 164 | var provider = new GitProviderLibGit2Sharp(); 165 | provider.Init(contextPath); 166 | } 167 | 168 | return basePath; 169 | } 170 | 171 | 172 | public int OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved) 173 | { 174 | return VSConstants.S_OK; 175 | } 176 | 177 | public int OnBeforeCloseSolution(object pUnkReserved) 178 | { 179 | if (m_saveListener != null) 180 | { 181 | m_saveListener.Shutdown(); 182 | m_saveListener = null; 183 | } 184 | 185 | return VSConstants.S_OK; 186 | } 187 | 188 | public int OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy) 189 | { 190 | return VSConstants.S_OK; 191 | } 192 | 193 | public int OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel) 194 | { 195 | return VSConstants.S_OK; 196 | } 197 | 198 | public int OnQueryCloseSolution(object pUnkReserved, ref int pfCancel) 199 | { 200 | return VSConstants.S_OK; 201 | } 202 | 203 | public int OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel) 204 | { 205 | return VSConstants.S_OK; 206 | } 207 | 208 | #endregion 209 | 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Visual Studio/autogit/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | autogit 7 | Every save backed to a local git repo. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/App_Readme/LibGit2Sharp.LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2011-2013 LibGit2Sharp contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/App_Readme/LibGit2Sharp.README.md: -------------------------------------------------------------------------------- 1 | # LibGit2Sharp 2 | 3 | **LibGit2Sharp brings all the might and speed of [libgit2][0], a native Git implementation, to the managed world of .Net and Mono.** 4 | 5 | [0]: http://libgit2.github.com/ 6 | 7 | ## Online resources 8 | 9 | - [NuGet package][1] 10 | - [Source code][2] 11 | - [Continuous integration][3] 12 | 13 | [1]: http://nuget.org/List/Packages/LibGit2Sharp 14 | [2]: https://github.com/libgit2/libgit2sharp/ 15 | [3]: http://teamcity.codebetter.com/project.html?projectId=project127&guest=1 16 | 17 | ## Troubleshooting and support 18 | 19 | - Usage or programming related question? Post it on [StackOverflow][4] using the tag *libgit2sharp* 20 | - Found a bug or missing a feature? Feed the [issue tracker][5] 21 | - Announcements and related miscellanea through Twitter ([@libgit2sharp][6]) 22 | 23 | [4]: http://stackoverflow.com/questions/tagged/libgit2sharp 24 | [5]: https://github.com/libgit2/libgit2sharp/issues 25 | [6]: http://twitter.com/libgit2sharp 26 | 27 | ## Current project build status 28 | The [build][3] is generously hosted and run on the [CodeBetter TeamCity][7] infrastructure. 29 | 30 | | | Status of last build | 31 | | :------ | :------: | 32 | | **master** | [![master][8]][9] | 33 | | **vNext (Win x86)** | [![vNext x86][10]][11] | 34 | | **vNext (Win amd64)** | [![vNext amd64][12]][13] | 35 | | **vNext (Mono)** | [![vNext Mono][14]][15] | 36 | 37 | [7]: http://codebetter.com/codebetter-ci/ 38 | [8]: http://teamcity.codebetter.com/app/rest/builds/buildType:(id:bt398)/statusIcon 39 | [9]: http://teamcity.codebetter.com/viewType.html?buildTypeId=bt398&guest=1 40 | [10]: http://teamcity.codebetter.com/app/rest/builds/buildType:(id:bt651)/statusIcon 41 | [11]: http://teamcity.codebetter.com/viewType.html?buildTypeId=bt651&guest=1 42 | [12]: http://teamcity.codebetter.com/app/rest/builds/buildType:(id:bt652)/statusIcon 43 | [13]: http://teamcity.codebetter.com/viewType.html?buildTypeId=bt652&guest=1 44 | [14]: http://teamcity.codebetter.com/app/rest/builds/buildType:(id:bt656)/statusIcon 45 | [15]: http://teamcity.codebetter.com/viewType.html?buildTypeId=bt656&guest=1 46 | 47 | ## Quick contributing guide 48 | 49 | - Fork and clone locally 50 | - Create a topic specific branch. Add some nice feature. Do not forget the tests ;-) 51 | - Send a Pull Request to spread the fun! 52 | 53 | More thorough information available in the [wiki][16]. 54 | 55 | [16]: https://github.com/libgit2/libgit2sharp/wiki 56 | 57 | ## Authors 58 | 59 | - **Code:** The LibGit2Sharp [contributors][17] 60 | - **Logo:** [Jason "blackant" Long][18] 61 | 62 | [17]: https://github.com/libgit2/libgit2sharp/contributors 63 | [18]: https://github.com/jasonlong 64 | 65 | ## License 66 | 67 | The MIT license (Refer to the [LICENSE.md][19] file) 68 | 69 | [19]: https://github.com/libgit2/libgit2sharp/blob/master/LICENSE.md 70 | -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/LibGit2Sharp.0.13.0.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/packages/LibGit2Sharp.0.13.0.0/LibGit2Sharp.0.13.0.0.nupkg -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/LibGit2Sharp.0.13.0.0.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LibGit2Sharp 5 | 0.13.0.0 6 | LibGit2Sharp 7 | LibGit2Sharp contributors 8 | LibGit2Sharp contributors 9 | https://github.com/libgit2/libgit2sharp/raw/master/LICENSE.md 10 | https://github.com/libgit2/libgit2sharp/ 11 | https://github.com/libgit2/libgit2sharp/raw/master/square-logo.png 12 | false 13 | LibGit2Sharp brings all the might and speed of libgit2, a native Git implementation, to the managed world of .Net and Mono. 14 | 15 | 16 | 17 | libgit2 git wrapper bindings API dvcs vcs 18 | 19 | -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/NativeBinaries/amd64/git2-7940036.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/packages/LibGit2Sharp.0.13.0.0/NativeBinaries/amd64/git2-7940036.dll -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/NativeBinaries/x86/git2-7940036.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/packages/LibGit2Sharp.0.13.0.0/NativeBinaries/x86/git2-7940036.dll -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/Tools/GetLibGit2SharpPostBuildCmd.ps1: -------------------------------------------------------------------------------- 1 | $solutionDir = [System.IO.Path]::GetDirectoryName($dte.Solution.FullName) + "\" 2 | $path = $installPath.Replace($solutionDir, "`$(SolutionDir)") 3 | 4 | $NativeAssembliesDir = Join-Path $path "NativeBinaries" 5 | $x86 = $(Join-Path $NativeAssembliesDir "x86\*.*") 6 | $x64 = $(Join-Path $NativeAssembliesDir "amd64\*.*") 7 | 8 | $LibGit2SharpPostBuildCmd = " 9 | if not exist `"`$(TargetDir)NativeBinaries`" md `"`$(TargetDir)NativeBinaries`" 10 | if not exist `"`$(TargetDir)NativeBinaries\x86`" md `"`$(TargetDir)NativeBinaries\x86`" 11 | xcopy /s /y `"$x86`" `"`$(TargetDir)NativeBinaries\x86`" 12 | if not exist `"`$(TargetDir)NativeBinaries\amd64`" md `"`$(TargetDir)NativeBinaries\amd64`" 13 | xcopy /s /y `"$x64`" `"`$(TargetDir)NativeBinaries\amd64`"" -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/Tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | . (Join-Path $toolsPath "GetLibGit2SharpPostBuildCmd.ps1") 4 | 5 | # Get the current Post Build Event cmd 6 | $currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value 7 | 8 | # Append our post build command if it's not already there 9 | if (!$currentPostBuildCmd.Contains($LibGit2SharpPostBuildCmd)) { 10 | $project.Properties.Item("PostBuildEvent").Value += $LibGit2SharpPostBuildCmd 11 | } -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/Tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | . (Join-Path $toolsPath "GetLibGit2SharpPostBuildCmd.ps1") 4 | 5 | # Get the current Post Build Event cmd 6 | $currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value 7 | 8 | # Remove our post build command from it (if it's there) 9 | $project.Properties.Item("PostBuildEvent").Value = $currentPostBuildCmd.Replace($LibGit2SharpPostBuildCmd, "") -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/LibGit2Sharp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/LibGit2Sharp.dll -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/LibGit2Sharp.dll.unsigned: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/LibGit2Sharp.dll.unsigned -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/LibGit2Sharp.libgit2_hash.txt: -------------------------------------------------------------------------------- 1 | 794003650e041668405a5ee12a7f763dca951758 2 | -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/LibGit2Sharp.libgit2sharp_hash.txt: -------------------------------------------------------------------------------- 1 | 9f0daeb6f6973f091a33238282766cb667bce111 2 | -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/LibGit2Sharp.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/LibGit2Sharp.res -------------------------------------------------------------------------------- /Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/keyPair.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisparnin/autogit/9b1e4f5ea5e1dc496545b95000289ce5c0998e72/Visual Studio/packages/LibGit2Sharp.0.13.0.0/lib/net35/keyPair.snk -------------------------------------------------------------------------------- /Visual Studio/packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------