# -*- coding: utf-8 -*- # # Copyright 2010-2014 The pygit2 contributors # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, # as published by the Free Software Foundation. # # In addition to the permissions in the GNU General Public License, # the authors give you unlimited permission to link the compiled # version of this file into combinations with other programs, # and to distribute those combinations without any restriction # coming from the use of this file. (The General Public License # restrictions do apply in other respects; for example, they cover # modification of the file, and distribution when not linked into # a combined executable.) # # This file is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. # Import from the future from __future__ import absolute_import # Low level API from _pygit2 import * # High level API from .blame import Blame, BlameHunk from .config import Config from .credentials import * from .errors import check_error from .ffi import ffi, C from .index import Index, IndexEntry from .remote import Remote, get_credentials from .repository import Repository from .settings import Settings from .utils import to_bytes, to_str from ._utils import __version__ # Features features = C.git_libgit2_features() GIT_FEATURE_THREADS = C.GIT_FEATURE_THREADS GIT_FEATURE_HTTPS = C.GIT_FEATURE_HTTPS GIT_FEATURE_SSH = C.GIT_FEATURE_SSH # GIT_REPOSITORY_INIT_* GIT_REPOSITORY_INIT_OPTIONS_VERSION = C.GIT_REPOSITORY_INIT_OPTIONS_VERSION GIT_REPOSITORY_INIT_BARE = C.GIT_REPOSITORY_INIT_BARE GIT_REPOSITORY_INIT_NO_REINIT = C.GIT_REPOSITORY_INIT_NO_REINIT GIT_REPOSITORY_INIT_NO_DOTGIT_DIR = C.GIT_REPOSITORY_INIT_NO_DOTGIT_DIR GIT_REPOSITORY_INIT_MKDIR = C.GIT_REPOSITORY_INIT_MKDIR GIT_REPOSITORY_INIT_MKPATH = C.GIT_REPOSITORY_INIT_MKPATH GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE = C.GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE GIT_REPOSITORY_INIT_RELATIVE_GITLINK = C.GIT_REPOSITORY_INIT_RELATIVE_GITLINK GIT_REPOSITORY_INIT_SHARED_UMASK = C.GIT_REPOSITORY_INIT_SHARED_UMASK GIT_REPOSITORY_INIT_SHARED_GROUP = C.GIT_REPOSITORY_INIT_SHARED_GROUP GIT_REPOSITORY_INIT_SHARED_ALL = C.GIT_REPOSITORY_INIT_SHARED_ALL def init_repository(path, bare=False, flags=GIT_REPOSITORY_INIT_MKPATH, mode=0, workdir_path=None, description=None, template_path=None, initial_head=None, origin_url=None): """ Creates a new Git repository in the given *path*. If *bare* is True the repository will be bare, i.e. it will not have a working copy. The *flags* may be a combination of: - GIT_REPOSITORY_INIT_BARE (overriden by the *bare* parameter) - GIT_REPOSITORY_INIT_NO_REINIT - GIT_REPOSITORY_INIT_NO_DOTGIT_DIR - GIT_REPOSITORY_INIT_MKDIR - GIT_REPOSITORY_INIT_MKPATH (set by default) - GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE The *mode* parameter may be any of GIT_REPOSITORY_SHARED_UMASK (default), GIT_REPOSITORY_SHARED_GROUP or GIT_REPOSITORY_INIT_SHARED_ALL, or a custom value. The *workdir_path*, *description*, *template_path*, *initial_head* and *origin_url* are all strings. See libgit2's documentation on git_repository_init_ext for further details. """ # Pre-process input parameters if bare: flags |= GIT_REPOSITORY_INIT_BARE # Options options = ffi.new('git_repository_init_options *') C.git_repository_init_init_options(options, GIT_REPOSITORY_INIT_OPTIONS_VERSION) options.flags = flags options.mode = mode if workdir_path: workdir_path_ref = ffi.new('char []', to_bytes(workdir_path)) options.workdir_path = workdir_path_ref if description: description_ref = ffi.new('char []', to_bytes(description)) options.description = description_ref if template_path: template_path_ref = ffi.new('char []', to_bytes(template_path)) options.template_path = template_path_ref if initial_head: initial_head_ref = ffi.new('char []', to_bytes(initial_head)) options.initial_head = initial_head_ref if origin_url: origin_url_ref = ffi.new('char []', to_bytes(origin_url)) options.origin_url = origin_url_ref # Call crepository = ffi.new('git_repository **') err = C.git_repository_init_ext(crepository, to_bytes(path), options) check_error(err) # Ok return Repository(to_str(path)) @ffi.callback('int (*credentials)(git_cred **cred, const char *url,' 'const char *username_from_url, unsigned int allowed_types,' 'void *data)') def _credentials_cb(cred_out, url, username_from_url, allowed, data): d = ffi.from_handle(data) try: ccred = get_credentials(d['credentials_cb'], url, username_from_url, allowed) cred_out[0] = ccred[0] except Exception as e: d['exception'] = e return C.GIT_EUSER return 0 @ffi.callback('int (*git_repository_create_cb)(git_repository **out,' 'const char *path, int bare, void *payload)') def _repository_create_cb(repo_out, path, bare, data): d = ffi.from_handle(data) try: repository = d['repository_cb'](ffi.string(path), bare != 0) # we no longer own the C object repository._disown() repo_out[0] = repository._repo except Exception as e: d['exception'] = e return C.GIT_EUSER return 0 @ffi.callback('int (*git_remote_create_cb)(git_remote **out, git_repository *repo,' 'const char *name, const char *url, void *payload)') def _remote_create_cb(remote_out, repo, name, url, data): d = ffi.from_handle(data) try: remote = d['remote_cb'](Repository._from_c(repo, False), ffi.string(name), ffi.string(url)) remote_out[0] = remote._remote # we no longer own the C object remote._remote = ffi.NULL except Exception as e: d['exception'] = e return C.GIT_EUSER return 0 @ffi.callback('int (*git_transport_certificate_check_cb)' '(git_cert *cert, int valid, const char *host, void *payload)') def _certificate_cb(cert_i, valid, host, data): d = ffi.from_handle(data) try: # python's parting is deep in the libraries and assumes an OpenSSL-owned cert val = d['certificate_cb'](None, bool(valid), ffi.string(host)) if not val: return C.GIT_ECERTIFICATE except Exception as e: d['exception'] = e return C.GIT_EUSER return 0 def clone_repository( url, path, bare=False, repository=None, remote=None, checkout_branch=None, credentials=None, certificate=None): """Clones a new Git repository from *url* in the given *path*. Returns a Repository class pointing to the newly cloned repository. :param str url: URL of the repository to clone :param str path: Local path to clone into :param bool bare: Whether the local repository should be bare :param callable remote: Callback for the remote to use. :param callable repository: Callback for the repository to use. :param str checkout_branch: Branch to checkout after the clone. The default is to use the remote's default branch. :param callable credentials: authentication to use if the remote requires it :param callable certificate: callback to verify the host's certificate or fingerprint. :rtype: Repository The repository callback has `(path, bare) -> Repository` as a signature. The Repository it returns will be used instead of creating a new one. The remote callback has `(Repository, name, url) -> Remote` as a signature. The Remote it returns will be used instead of the default one. The certificate callback has `(cert, valid, hostname) -> bool` as a signature. Return True to accept the connection, False to abort. """ opts = ffi.new('git_clone_options *') crepo = ffi.new('git_repository **') branch = checkout_branch or None # Data, let's use a dict as we don't really want much more d = {} d['credentials_cb'] = credentials d['repository_cb'] = repository d['remote_cb'] = remote d['certificate_cb'] = certificate d_handle = ffi.new_handle(d) # Perform the initialization with the version we compiled C.git_clone_init_options(opts, C.GIT_CLONE_OPTIONS_VERSION) # We need to keep the ref alive ourselves checkout_branch_ref = None if branch: checkout_branch_ref = ffi.new('char []', to_bytes(branch)) opts.checkout_branch = checkout_branch_ref if repository: opts.repository_cb = _repository_create_cb opts.repository_cb_payload = d_handle if remote: opts.remote_cb = _remote_create_cb opts.remote_cb_payload = d_handle opts.bare = bare if credentials: opts.remote_callbacks.credentials = _credentials_cb opts.remote_callbacks.payload = d_handle if certificate: opts.remote_callbacks.certificate_check = _certificate_cb opts.remote_callbacks.payload = d_handle err = C.git_clone(crepo, to_bytes(url), to_bytes(path), opts) if 'exception' in d: raise d['exception'] check_error(err) return Repository._from_c(crepo[0], owned=True) settings = Settings()