mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
Merge branch 'main' into typos
This commit is contained in:
17
ci/test.sh
17
ci/test.sh
@@ -83,7 +83,7 @@ echo "##########################################################################
|
||||
if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
|
||||
echo "Starting git daemon..."
|
||||
GITDAEMON_DIR=`mktemp -d ${TMPDIR}/gitdaemon.XXXXXXXX`
|
||||
git init --bare "${GITDAEMON_DIR}/test.git"
|
||||
git init --bare "${GITDAEMON_DIR}/test.git" >/dev/null
|
||||
git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GITDAEMON_DIR}" "${GITDAEMON_DIR}" 2>/dev/null &
|
||||
GITDAEMON_PID=$!
|
||||
disown $GITDAEMON_PID
|
||||
@@ -101,8 +101,8 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then
|
||||
java -jar poxyproxy.jar --address 127.0.0.1 --port 8090 --credentials foo:bar --auth-type ntlm --quiet &
|
||||
fi
|
||||
|
||||
if [ -z "$SKIP_NTLM_TESTS" ]; then
|
||||
curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.4.0/poxygit-0.4.0.jar >poxygit.jar
|
||||
if [ -z "$SKIP_NTLM_TESTS" -o -z "$SKIP_ONLINE_TESTS" ]; then
|
||||
curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.5.1/poxygit-0.5.1.jar >poxygit.jar
|
||||
|
||||
echo ""
|
||||
echo "Starting HTTP server..."
|
||||
@@ -112,10 +112,11 @@ if [ -z "$SKIP_NTLM_TESTS" ]; then
|
||||
fi
|
||||
|
||||
if [ -z "$SKIP_SSH_TESTS" ]; then
|
||||
echo ""
|
||||
echo "Starting ssh daemon..."
|
||||
HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX`
|
||||
SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX`
|
||||
git init --bare "${SSHD_DIR}/test.git"
|
||||
git init --bare "${SSHD_DIR}/test.git" >/dev/null
|
||||
cat >"${SSHD_DIR}/sshd_config" <<-EOF
|
||||
Port 2222
|
||||
ListenAddress 0.0.0.0
|
||||
@@ -188,9 +189,11 @@ if [ -z "$SKIP_ONLINE_TESTS" ]; then
|
||||
echo "## Running (online) tests"
|
||||
echo "##############################################################################"
|
||||
|
||||
export GITTEST_FLAKY_RETRY=5
|
||||
export GITTEST_REMOTE_REDIRECT_INITIAL="http://localhost:9000/initial-redirect/libgit2/TestGitRepository"
|
||||
export GITTEST_REMOTE_REDIRECT_SUBSEQUENT="http://localhost:9000/subsequent-redirect/libgit2/TestGitRepository"
|
||||
run_test online
|
||||
unset GITTEST_FLAKY_RETRY
|
||||
unset GITTEST_REMOTE_REDIRECT_INITIAL
|
||||
unset GITTEST_REMOTE_REDIRECT_SUBSEQUENT
|
||||
|
||||
# Run the online tests that immutably change global state separately
|
||||
# to avoid polluting the test environment.
|
||||
@@ -231,9 +234,7 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then
|
||||
export GITTEST_REMOTE_PROXY_HOST="localhost:8090"
|
||||
export GITTEST_REMOTE_PROXY_USER="foo"
|
||||
export GITTEST_REMOTE_PROXY_PASS="bar"
|
||||
export GITTEST_FLAKY_RETRY=5
|
||||
run_test proxy
|
||||
unset GITTEST_FLAKY_RETRY
|
||||
unset GITTEST_REMOTE_PROXY_HOST
|
||||
unset GITTEST_REMOTE_PROXY_USER
|
||||
unset GITTEST_REMOTE_PROXY_PASS
|
||||
|
||||
63
docs/api-stability.md
Normal file
63
docs/api-stability.md
Normal file
@@ -0,0 +1,63 @@
|
||||
The maintainers of the libgit2 project believe that having a stable API
|
||||
to program against is important for our users and the ecosystem - whether
|
||||
you're building against the libgit2 C APIs directly, creating a wrapper to
|
||||
a managed language, or programming against one of those managed wrappers
|
||||
like LibGit2Sharp or Rugged.
|
||||
|
||||
Our API stability considerations are:
|
||||
|
||||
* Our standard API is considered stable through a major release.
|
||||
|
||||
* We define our "standard API" to be anything included in the "git2.h"
|
||||
header - in other words, anything defined in a header in the `git2`
|
||||
directory.
|
||||
|
||||
* APIs will maintain their signature and will not be removed within a
|
||||
major release, but new APIs may be added.
|
||||
|
||||
* Any APIs may be marked as deprecated within a major release, but will
|
||||
not be removed until the next major release (at the earliest). You
|
||||
may define `GIT_DEPRECATE_HARD` to produce compiler warnings if you
|
||||
target these deprecated APIs.
|
||||
|
||||
* We consider API compatibility to be against the C APIs. That means
|
||||
that we may use macros to keep API compatibility - for example, if we
|
||||
rename a structure from `git_widget_options` to `git_foobar_options`
|
||||
then we would `#define git_widget_options git_foobar_options` to retain
|
||||
API compatibility. Note that this does _not_ provide ABI compatibility.
|
||||
|
||||
* Our systems API is only considered stable through a _minor_ release.
|
||||
|
||||
* We define our "systems API" to be anything included in the `git2/sys`
|
||||
directory. These are not "standard" APIs but are mechanisms to extend
|
||||
libgit2 by adding new extensions - for example, a custom HTTPS transport,
|
||||
TLS engine, or merge strategy.
|
||||
|
||||
* Additionally, the cmake options and the resulting constants that it
|
||||
produces to be "systems API".
|
||||
|
||||
* Generally these mechanism are well defined and will not need significant
|
||||
changes, but are considered a part of the library itself and may need
|
||||
|
||||
* Systems API changes will be noted specially within a release's changelog.
|
||||
|
||||
* Our ABI is only considered stable through a _minor_ release.
|
||||
|
||||
* Our ABI consists of actual symbol names in the library, the function
|
||||
signatures, and the actual layout of structures. These are only
|
||||
stable within minor releases, they are not stable within major releases
|
||||
(yet).
|
||||
|
||||
* Since many FFIs use ABIs directly (for example, .NET P/Invoke or Rust),
|
||||
this instability is unfortunate.
|
||||
|
||||
* In a future major release, we will begin providing ABI stability
|
||||
throughout the major release cycle.
|
||||
|
||||
* ABI changes will be noted specially within a release's changelog.
|
||||
|
||||
* Point releases are _generally_ only for bugfixes, and generally do _not_
|
||||
include new features. This means that point releases generally do _not_
|
||||
include new APIs. Point releases will never break API, systems API or
|
||||
ABI compatibility.
|
||||
|
||||
@@ -41,6 +41,30 @@ GIT_EXTERN(int) git_remote_create(
|
||||
const char *name,
|
||||
const char *url);
|
||||
|
||||
/**
|
||||
* Remote redirection settings; whether redirects to another host
|
||||
* are permitted. By default, git will follow a redirect on the
|
||||
* initial request (`/info/refs`), but not subsequent requests.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* Do not follow any off-site redirects at any stage of
|
||||
* the fetch or push.
|
||||
*/
|
||||
GIT_REMOTE_REDIRECT_NONE = (1 << 0),
|
||||
|
||||
/**
|
||||
* Allow off-site redirects only upon the initial request.
|
||||
* This is the default.
|
||||
*/
|
||||
GIT_REMOTE_REDIRECT_INITIAL = (1 << 1),
|
||||
|
||||
/**
|
||||
* Allow redirects at any stage in the fetch or push.
|
||||
*/
|
||||
GIT_REMOTE_REDIRECT_ALL = (1 << 2)
|
||||
} git_remote_redirect_t;
|
||||
|
||||
/**
|
||||
* Remote creation options flags
|
||||
*/
|
||||
@@ -344,23 +368,6 @@ GIT_EXTERN(size_t) git_remote_refspec_count(const git_remote *remote);
|
||||
*/
|
||||
GIT_EXTERN(const git_refspec *)git_remote_get_refspec(const git_remote *remote, size_t n);
|
||||
|
||||
/**
|
||||
* Open a connection to a remote
|
||||
*
|
||||
* The transport is selected based on the URL. The direction argument
|
||||
* is due to a limitation of the git protocol (over TCP or SSH) which
|
||||
* starts up a specific binary which can only do the one or the other.
|
||||
*
|
||||
* @param remote the remote to connect to
|
||||
* @param direction GIT_DIRECTION_FETCH if you want to fetch or
|
||||
* GIT_DIRECTION_PUSH if you want to push
|
||||
* @param callbacks the callbacks to use for this connection
|
||||
* @param proxy_opts proxy settings
|
||||
* @param custom_headers extra HTTP headers to use in this connection
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_proxy_options *proxy_opts, const git_strarray *custom_headers);
|
||||
|
||||
/**
|
||||
* Get the remote repository's reference advertisement list
|
||||
*
|
||||
@@ -734,6 +741,13 @@ typedef struct {
|
||||
*/
|
||||
git_proxy_options proxy_opts;
|
||||
|
||||
/**
|
||||
* Whether to allow off-site redirects. If this is not
|
||||
* specified, the `http.followRedirects` configuration setting
|
||||
* will be consulted.
|
||||
*/
|
||||
git_remote_redirect_t follow_redirects;
|
||||
|
||||
/**
|
||||
* Extra headers for this fetch operation
|
||||
*/
|
||||
@@ -785,6 +799,13 @@ typedef struct {
|
||||
*/
|
||||
git_proxy_options proxy_opts;
|
||||
|
||||
/**
|
||||
* Whether to allow off-site redirects. If this is not
|
||||
* specified, the `http.followRedirects` configuration setting
|
||||
* will be consulted.
|
||||
*/
|
||||
git_remote_redirect_t follow_redirects;
|
||||
|
||||
/**
|
||||
* Extra headers for this push operation
|
||||
*/
|
||||
@@ -809,7 +830,100 @@ GIT_EXTERN(int) git_push_options_init(
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Download and index the packfile
|
||||
* Remote creation options structure
|
||||
*
|
||||
* Initialize with `GIT_REMOTE_CREATE_OPTIONS_INIT`. Alternatively, you can
|
||||
* use `git_remote_create_options_init`.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
/** Callbacks to use for this connection */
|
||||
git_remote_callbacks callbacks;
|
||||
|
||||
/** HTTP Proxy settings */
|
||||
git_proxy_options proxy_opts;
|
||||
|
||||
/**
|
||||
* Whether to allow off-site redirects. If this is not
|
||||
* specified, the `http.followRedirects` configuration setting
|
||||
* will be consulted.
|
||||
*/
|
||||
git_remote_redirect_t follow_redirects;
|
||||
|
||||
/** Extra HTTP headers to use in this connection */
|
||||
git_strarray custom_headers;
|
||||
} git_remote_connect_options;
|
||||
|
||||
#define GIT_REMOTE_CONNECT_OPTIONS_VERSION 1
|
||||
#define GIT_REMOTE_CONNECT_OPTIONS_INIT { \
|
||||
GIT_REMOTE_CONNECT_OPTIONS_VERSION, \
|
||||
GIT_REMOTE_CALLBACKS_INIT, \
|
||||
GIT_PROXY_OPTIONS_INIT }
|
||||
|
||||
/**
|
||||
* Initialize git_remote_connect_options structure.
|
||||
*
|
||||
* Initializes a `git_remote_connect_options` with default values.
|
||||
* Equivalent to creating an instance with
|
||||
* `GIT_REMOTE_CONNECT_OPTIONS_INIT`.
|
||||
*
|
||||
* @param opts The `git_remote_connect_options` struct to initialize.
|
||||
* @param version The struct version; pass `GIT_REMOTE_CONNECT_OPTIONS_VERSION`.
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_connect_options_init(
|
||||
git_remote_connect_options *opts,
|
||||
unsigned int version);
|
||||
|
||||
/**
|
||||
* Open a connection to a remote.
|
||||
*
|
||||
* The transport is selected based on the URL; the direction argument
|
||||
* is due to a limitation of the git protocol which starts up a
|
||||
* specific binary which can only do the one or the other.
|
||||
*
|
||||
* @param remote the remote to connect to
|
||||
* @param direction GIT_DIRECTION_FETCH if you want to fetch or
|
||||
* GIT_DIRECTION_PUSH if you want to push
|
||||
* @param callbacks the callbacks to use for this connection
|
||||
* @param proxy_opts proxy settings
|
||||
* @param custom_headers extra HTTP headers to use in this connection
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_connect(
|
||||
git_remote *remote,
|
||||
git_direction direction,
|
||||
const git_remote_callbacks *callbacks,
|
||||
const git_proxy_options *proxy_opts,
|
||||
const git_strarray *custom_headers);
|
||||
|
||||
/**
|
||||
* Open a connection to a remote with extended options.
|
||||
*
|
||||
* The transport is selected based on the URL; the direction argument
|
||||
* is due to a limitation of the git protocol which starts up a
|
||||
* specific binary which can only do the one or the other.
|
||||
*
|
||||
* The given options structure will form the defaults for connection
|
||||
* options and callback setup. Callers may override these defaults
|
||||
* by specifying `git_fetch_options` or `git_push_options` in
|
||||
* subsequent calls.
|
||||
*
|
||||
* @param remote the remote to connect to
|
||||
* @param direction GIT_DIRECTION_FETCH if you want to fetch or
|
||||
* GIT_DIRECTION_PUSH if you want to push
|
||||
* @param opts the remote connection options
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_connect_ext(
|
||||
git_remote *remote,
|
||||
git_direction direction,
|
||||
const git_remote_connect_options *opts);
|
||||
|
||||
/**
|
||||
* Download and index the packfile.
|
||||
*
|
||||
* Connect to the remote if it hasn't been done yet, negotiate with
|
||||
* the remote git which objects are missing, download and index the
|
||||
@@ -818,19 +932,31 @@ GIT_EXTERN(int) git_push_options_init(
|
||||
* The .idx file will be created and both it and the packfile with be
|
||||
* renamed to their final name.
|
||||
*
|
||||
* If options are specified and this remote is already connected then
|
||||
* the existing remote connection options will be discarded and the
|
||||
* remote will now use the new options.
|
||||
*
|
||||
* @param remote the remote
|
||||
* @param refspecs the refspecs to use for this negotiation and
|
||||
* download. Use NULL or an empty array to use the base refspecs
|
||||
* @param opts the options to use for this fetch
|
||||
* @param opts the options to use for this fetch or NULL
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts);
|
||||
GIT_EXTERN(int) git_remote_download(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_fetch_options *opts);
|
||||
|
||||
/**
|
||||
* Create a packfile and send it to the server
|
||||
*
|
||||
* Connect to the remote if it hasn't been done yet, negotiate with
|
||||
* the remote git which objects are missing, create a packfile with the missing objects and send it.
|
||||
* the remote git which objects are missing, create a packfile with
|
||||
* the missing objects and send it.
|
||||
*
|
||||
* If options are specified and this remote is already connected then
|
||||
* the existing remote connection options will be discarded and the
|
||||
* remote will now use the new options.
|
||||
*
|
||||
* @param remote the remote
|
||||
* @param refspecs the refspecs to use for this negotiation and
|
||||
@@ -838,17 +964,23 @@ GIT_EXTERN(int) git_push_options_init(
|
||||
* @param opts the options to use for this push
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts);
|
||||
GIT_EXTERN(int) git_remote_upload(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_push_options *opts);
|
||||
|
||||
/**
|
||||
* Update the tips to the new state
|
||||
* Update the tips to the new state.
|
||||
*
|
||||
* If callbacks are not specified then the callbacks specified to
|
||||
* `git_remote_connect` will be used (if it was called).
|
||||
*
|
||||
* @param remote the remote to update
|
||||
* @param reflog_message The message to insert into the reflogs. If
|
||||
* NULL and fetching, the default is "fetch <name>", where <name> is
|
||||
* the name of the remote (or its url, for in-memory remotes). This
|
||||
* parameter is ignored when pushing.
|
||||
* @param callbacks pointer to the callback structure to use
|
||||
* @param callbacks pointer to the callback structure to use or NULL
|
||||
* @param update_fetchhead whether to write to FETCH_HEAD. Pass 1 to behave like git.
|
||||
* @param download_tags what the behaviour for downloading tags is for this fetch. This is
|
||||
* ignored for push. This must be the same value passed to `git_remote_download()`.
|
||||
@@ -862,15 +994,19 @@ GIT_EXTERN(int) git_remote_update_tips(
|
||||
const char *reflog_message);
|
||||
|
||||
/**
|
||||
* Download new data and update tips
|
||||
* Download new data and update tips.
|
||||
*
|
||||
* Convenience function to connect to a remote, download the data,
|
||||
* disconnect and update the remote-tracking branches.
|
||||
*
|
||||
* If options are specified and this remote is already connected then
|
||||
* the existing remote connection options will be discarded and the
|
||||
* remote will now use the new options.
|
||||
*
|
||||
* @param remote the remote to fetch from
|
||||
* @param refspecs the refspecs to use for this fetch. Pass NULL or an
|
||||
* empty array to use the base refspecs.
|
||||
* @param opts options to use for this fetch
|
||||
* @param opts options to use for this fetch or NULL
|
||||
* @param reflog_message The message to insert into the reflogs. If NULL, the
|
||||
* default is "fetch"
|
||||
* @return 0 or an error code
|
||||
@@ -882,27 +1018,35 @@ GIT_EXTERN(int) git_remote_fetch(
|
||||
const char *reflog_message);
|
||||
|
||||
/**
|
||||
* Prune tracking refs that are no longer present on remote
|
||||
* Prune tracking refs that are no longer present on remote.
|
||||
*
|
||||
* If callbacks are not specified then the callbacks specified to
|
||||
* `git_remote_connect` will be used (if it was called).
|
||||
*
|
||||
* @param remote the remote to prune
|
||||
* @param callbacks callbacks to use for this prune
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks);
|
||||
GIT_EXTERN(int) git_remote_prune(
|
||||
git_remote *remote,
|
||||
const git_remote_callbacks *callbacks);
|
||||
|
||||
/**
|
||||
* Perform a push
|
||||
* Perform a push.
|
||||
*
|
||||
* Perform all the steps from a push.
|
||||
* If options are specified and this remote is already connected then
|
||||
* the existing remote connection options will be discarded and the
|
||||
* remote will now use the new options.
|
||||
*
|
||||
* @param remote the remote to push to
|
||||
* @param refspecs the refspecs to use for pushing. If NULL or an empty
|
||||
* array, the configured refspecs will be used
|
||||
* @param opts options to use for this push
|
||||
*/
|
||||
GIT_EXTERN(int) git_remote_push(git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_push_options *opts);
|
||||
GIT_EXTERN(int) git_remote_push(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_push_options *opts);
|
||||
|
||||
/**
|
||||
* Get the statistics structure that is filled in by the fetch operation.
|
||||
|
||||
@@ -250,6 +250,12 @@ typedef struct {
|
||||
* working directory and index; defaults to HEAD.
|
||||
*/
|
||||
git_tree *baseline;
|
||||
|
||||
/**
|
||||
* Threshold above which similar files will be considered renames.
|
||||
* This is equivalent to the -M option. Defaults to 50.
|
||||
*/
|
||||
uint16_t rename_threshold;
|
||||
} git_status_options;
|
||||
|
||||
#define GIT_STATUS_OPTIONS_VERSION 1
|
||||
|
||||
@@ -24,31 +24,9 @@
|
||||
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Flags to pass to transport
|
||||
*
|
||||
* Currently unused.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_TRANSPORTFLAGS_NONE = 0
|
||||
} git_transport_flags_t;
|
||||
|
||||
struct git_transport {
|
||||
unsigned int version; /**< The struct version */
|
||||
|
||||
/** Set progress and error callbacks */
|
||||
int GIT_CALLBACK(set_callbacks)(
|
||||
git_transport *transport,
|
||||
git_transport_message_cb progress_cb,
|
||||
git_transport_message_cb error_cb,
|
||||
git_transport_certificate_check_cb certificate_check_cb,
|
||||
void *payload);
|
||||
|
||||
/** Set custom headers for HTTP requests */
|
||||
int GIT_CALLBACK(set_custom_headers)(
|
||||
git_transport *transport,
|
||||
const git_strarray *custom_headers);
|
||||
|
||||
/**
|
||||
* Connect the transport to the remote repository, using the given
|
||||
* direction.
|
||||
@@ -56,11 +34,17 @@ struct git_transport {
|
||||
int GIT_CALLBACK(connect)(
|
||||
git_transport *transport,
|
||||
const char *url,
|
||||
git_credential_acquire_cb cred_acquire_cb,
|
||||
void *cred_acquire_payload,
|
||||
const git_proxy_options *proxy_opts,
|
||||
int direction,
|
||||
int flags);
|
||||
const git_remote_connect_options *connect_opts);
|
||||
|
||||
/**
|
||||
* Resets the connect options for the given transport. This
|
||||
* is useful for updating settings or callbacks for an already
|
||||
* connected transport.
|
||||
*/
|
||||
int GIT_CALLBACK(set_connect_opts)(
|
||||
git_transport *transport,
|
||||
const git_remote_connect_options *connect_opts);
|
||||
|
||||
/**
|
||||
* Get the list of available references in the remote repository.
|
||||
@@ -75,7 +59,9 @@ struct git_transport {
|
||||
git_transport *transport);
|
||||
|
||||
/** Executes the push whose context is in the git_push object. */
|
||||
int GIT_CALLBACK(push)(git_transport *transport, git_push *push, const git_remote_callbacks *callbacks);
|
||||
int GIT_CALLBACK(push)(
|
||||
git_transport *transport,
|
||||
git_push *push);
|
||||
|
||||
/**
|
||||
* Negotiate a fetch with the remote repository.
|
||||
@@ -99,16 +85,11 @@ struct git_transport {
|
||||
int GIT_CALLBACK(download_pack)(
|
||||
git_transport *transport,
|
||||
git_repository *repo,
|
||||
git_indexer_progress *stats,
|
||||
git_indexer_progress_cb progress_cb,
|
||||
void *progress_payload);
|
||||
git_indexer_progress *stats);
|
||||
|
||||
/** Checks to see if the transport is connected */
|
||||
int GIT_CALLBACK(is_connected)(git_transport *transport);
|
||||
|
||||
/** Reads the flags value previously passed into connect() */
|
||||
int GIT_CALLBACK(read_flags)(git_transport *transport, int *flags);
|
||||
|
||||
/** Cancels any outstanding transport operation */
|
||||
void GIT_CALLBACK(cancel)(git_transport *transport);
|
||||
|
||||
|
||||
@@ -81,11 +81,11 @@ typedef struct {
|
||||
const git_index_entry *ours;
|
||||
const git_index_entry *theirs;
|
||||
|
||||
int name_collision:1,
|
||||
directoryfile:1,
|
||||
one_to_two:1,
|
||||
binary:1,
|
||||
submodule:1;
|
||||
unsigned int name_collision:1,
|
||||
directoryfile:1,
|
||||
one_to_two:1,
|
||||
binary:1,
|
||||
submodule:1;
|
||||
} checkout_conflictdata;
|
||||
|
||||
static int checkout_notify(
|
||||
|
||||
@@ -724,14 +724,25 @@ static const struct {
|
||||
static int parse_conditional_include(config_file_parse_data *parse_data, const char *section, const char *file)
|
||||
{
|
||||
char *condition;
|
||||
size_t i;
|
||||
size_t section_len, i;
|
||||
int error = 0, matches;
|
||||
|
||||
if (!parse_data->repo || !file)
|
||||
return 0;
|
||||
|
||||
condition = git__substrdup(section + strlen("includeIf."),
|
||||
strlen(section) - strlen("includeIf.") - strlen(".path"));
|
||||
section_len = strlen(section);
|
||||
|
||||
/*
|
||||
* We checked that the string starts with `includeIf.` and ends
|
||||
* in `.path` to get here. Make sure it consists of more.
|
||||
*/
|
||||
if (section_len < CONST_STRLEN("includeIf.") + CONST_STRLEN(".path"))
|
||||
return 0;
|
||||
|
||||
condition = git__substrdup(section + CONST_STRLEN("includeIf."),
|
||||
section_len - CONST_STRLEN("includeIf.") - CONST_STRLEN(".path"));
|
||||
|
||||
GIT_ERROR_CHECK_ALLOC(condition);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(conditions); i++) {
|
||||
if (git__prefixcmp(condition, conditions[i].prefix))
|
||||
|
||||
@@ -375,7 +375,7 @@ static int apply_splits_and_deletes(
|
||||
size_t i;
|
||||
git_diff_delta *delta;
|
||||
|
||||
if (git_vector_init(&onto, expected_size, git_diff_delta__cmp) < 0)
|
||||
if (git_vector_init(&onto, expected_size, diff->deltas._cmp) < 0)
|
||||
return -1;
|
||||
|
||||
/* build new delta list without TO_DELETE and splitting TO_SPLIT */
|
||||
|
||||
15
src/fetch.c
15
src/fetch.c
@@ -87,10 +87,10 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
|
||||
if ((error = git_repository_odb__weakptr(&odb, remote->repo)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
|
||||
if ((error = git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < heads_len; i++) {
|
||||
@@ -134,21 +134,14 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
|
||||
remote->refs.length);
|
||||
}
|
||||
|
||||
int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *callbacks)
|
||||
int git_fetch_download_pack(git_remote *remote)
|
||||
{
|
||||
git_transport *t = remote->transport;
|
||||
git_indexer_progress_cb progress = NULL;
|
||||
void *payload = NULL;
|
||||
|
||||
if (!remote->need_pack)
|
||||
return 0;
|
||||
|
||||
if (callbacks) {
|
||||
progress = callbacks->transfer_progress;
|
||||
payload = callbacks->payload;
|
||||
}
|
||||
|
||||
return t->download_pack(t, remote->repo, &remote->stats, progress, payload);
|
||||
return t->download_pack(t, remote->repo, &remote->stats);
|
||||
}
|
||||
|
||||
int git_fetch_options_init(git_fetch_options *opts, unsigned int version)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts);
|
||||
|
||||
int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *callbacks);
|
||||
int git_fetch_download_pack(git_remote *remote);
|
||||
|
||||
int git_fetch_setup_walk(git_revwalk **out, git_repository *repo);
|
||||
|
||||
|
||||
@@ -315,6 +315,7 @@ static void remove_service_suffix(
|
||||
int git_net_url_apply_redirect(
|
||||
git_net_url *url,
|
||||
const char *redirect_location,
|
||||
bool allow_offsite,
|
||||
const char *service_suffix)
|
||||
{
|
||||
git_net_url tmp = GIT_NET_URL_INIT;
|
||||
@@ -339,8 +340,8 @@ int git_net_url_apply_redirect(
|
||||
/* Validate that this is a legal redirection */
|
||||
|
||||
if (original->scheme &&
|
||||
strcmp(original->scheme, tmp.scheme) != 0 &&
|
||||
strcmp(tmp.scheme, "https") != 0) {
|
||||
strcmp(original->scheme, tmp.scheme) != 0 &&
|
||||
strcmp(tmp.scheme, "https") != 0) {
|
||||
git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'",
|
||||
original->scheme, tmp.scheme);
|
||||
|
||||
@@ -349,6 +350,7 @@ int git_net_url_apply_redirect(
|
||||
}
|
||||
|
||||
if (original->host &&
|
||||
!allow_offsite &&
|
||||
git__strcasecmp(original->host, tmp.host) != 0) {
|
||||
git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'",
|
||||
original->host, tmp.host);
|
||||
|
||||
@@ -46,6 +46,7 @@ extern bool git_net_url_is_ipv6(git_net_url *url);
|
||||
extern int git_net_url_apply_redirect(
|
||||
git_net_url *url,
|
||||
const char *redirect_location,
|
||||
bool allow_offsite,
|
||||
const char *service_suffix);
|
||||
|
||||
/** Swaps the contents of one URL for another. */
|
||||
|
||||
@@ -46,10 +46,10 @@ typedef struct git_pobject {
|
||||
size_t delta_size;
|
||||
size_t z_delta_size;
|
||||
|
||||
int written:1,
|
||||
recursing:1,
|
||||
tagged:1,
|
||||
filled:1;
|
||||
unsigned int written:1,
|
||||
recursing:1,
|
||||
tagged:1,
|
||||
filled:1;
|
||||
} git_pobject;
|
||||
|
||||
struct git_packbuilder {
|
||||
|
||||
@@ -39,8 +39,11 @@ int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void git_proxy_options_clear(git_proxy_options *opts)
|
||||
void git_proxy_options_dispose(git_proxy_options *opts)
|
||||
{
|
||||
if (!opts)
|
||||
return;
|
||||
|
||||
git__free((char *) opts->url);
|
||||
opts->url = NULL;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
#include "git2/proxy.h"
|
||||
|
||||
extern int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src);
|
||||
extern void git_proxy_options_clear(git_proxy_options *opts);
|
||||
extern void git_proxy_options_dispose(git_proxy_options *opts);
|
||||
|
||||
#endif
|
||||
|
||||
51
src/push.c
51
src/push.c
@@ -29,19 +29,26 @@ static int push_status_ref_cmp(const void *a, const void *b)
|
||||
return strcmp(push_status_a->ref, push_status_b->ref);
|
||||
}
|
||||
|
||||
int git_push_new(git_push **out, git_remote *remote)
|
||||
int git_push_new(git_push **out, git_remote *remote, const git_push_options *opts)
|
||||
{
|
||||
git_push *p;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
GIT_ERROR_CHECK_VERSION(opts, GIT_PUSH_OPTIONS_VERSION, "git_push_options");
|
||||
|
||||
p = git__calloc(1, sizeof(*p));
|
||||
GIT_ERROR_CHECK_ALLOC(p);
|
||||
|
||||
p->repo = remote->repo;
|
||||
p->remote = remote;
|
||||
p->report_status = 1;
|
||||
p->pb_parallelism = 1;
|
||||
p->pb_parallelism = opts ? opts->pb_parallelism : 1;
|
||||
|
||||
if (opts) {
|
||||
GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
|
||||
memcpy(&p->callbacks, &opts->callbacks, sizeof(git_remote_callbacks));
|
||||
}
|
||||
|
||||
if (git_vector_init(&p->specs, 0, push_spec_rref_cmp) < 0) {
|
||||
git__free(p);
|
||||
@@ -65,20 +72,6 @@ int git_push_new(git_push **out, git_remote *remote)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_push_set_options(git_push *push, const git_push_options *opts)
|
||||
{
|
||||
if (!push || !opts)
|
||||
return -1;
|
||||
|
||||
GIT_ERROR_CHECK_VERSION(opts, GIT_PUSH_OPTIONS_VERSION, "git_push_options");
|
||||
|
||||
push->pb_parallelism = opts->pb_parallelism;
|
||||
push->connection.custom_headers = &opts->custom_headers;
|
||||
push->connection.proxy = &opts->proxy_opts;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_refspec(push_spec *spec)
|
||||
{
|
||||
if (spec == NULL)
|
||||
@@ -291,7 +284,7 @@ static int queue_objects(git_push *push)
|
||||
if (git_oid_equal(&spec->loid, &spec->roid))
|
||||
continue; /* up-to-date */
|
||||
|
||||
if (git_odb_read_header(&size, &type, push->repo->_odb, &spec->loid) < 0)
|
||||
if ((error = git_odb_read_header(&size, &type, push->repo->_odb, &spec->loid)) < 0)
|
||||
goto on_error;
|
||||
|
||||
if (type == GIT_OBJECT_TAG) {
|
||||
@@ -301,19 +294,19 @@ static int queue_objects(git_push *push)
|
||||
goto on_error;
|
||||
|
||||
if (git_object_type(target) == GIT_OBJECT_COMMIT) {
|
||||
if (git_revwalk_push(rw, git_object_id(target)) < 0) {
|
||||
if ((error = git_revwalk_push(rw, git_object_id(target))) < 0) {
|
||||
git_object_free(target);
|
||||
goto on_error;
|
||||
}
|
||||
} else {
|
||||
if (git_packbuilder_insert(
|
||||
push->pb, git_object_id(target), NULL) < 0) {
|
||||
if ((error = git_packbuilder_insert(
|
||||
push->pb, git_object_id(target), NULL)) < 0) {
|
||||
git_object_free(target);
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
git_object_free(target);
|
||||
} else if (git_revwalk_push(rw, &spec->loid) < 0)
|
||||
} else if ((error = git_revwalk_push(rw, &spec->loid)) < 0)
|
||||
goto on_error;
|
||||
|
||||
if (!spec->refspec.force) {
|
||||
@@ -411,10 +404,11 @@ static int calculate_work(git_push *push)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_push(git_push *push, const git_remote_callbacks *callbacks)
|
||||
static int do_push(git_push *push)
|
||||
{
|
||||
int error = 0;
|
||||
git_transport *transport = push->remote->transport;
|
||||
git_remote_callbacks *callbacks = &push->callbacks;
|
||||
|
||||
if (!transport->push) {
|
||||
git_error_set(GIT_ERROR_NET, "remote transport doesn't support push");
|
||||
@@ -446,7 +440,7 @@ static int do_push(git_push *push, const git_remote_callbacks *callbacks)
|
||||
goto on_error;
|
||||
|
||||
if ((error = queue_objects(push)) < 0 ||
|
||||
(error = transport->push(transport, push, callbacks)) < 0)
|
||||
(error = transport->push(transport, push)) < 0)
|
||||
goto on_error;
|
||||
|
||||
on_error:
|
||||
@@ -472,16 +466,17 @@ static int filter_refs(git_remote *remote)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_push_finish(git_push *push, const git_remote_callbacks *callbacks)
|
||||
int git_push_finish(git_push *push)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!git_remote_connected(push->remote) &&
|
||||
(error = git_remote__connect(push->remote, GIT_DIRECTION_PUSH, callbacks, &push->connection)) < 0)
|
||||
return error;
|
||||
if (!git_remote_connected(push->remote)) {
|
||||
git_error_set(GIT_ERROR_NET, "remote is disconnected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((error = filter_refs(push->remote)) < 0 ||
|
||||
(error = do_push(push, callbacks)) < 0)
|
||||
(error = do_push(push)) < 0)
|
||||
return error;
|
||||
|
||||
if (!push->unpack_ok) {
|
||||
|
||||
20
src/push.h
20
src/push.h
@@ -41,7 +41,7 @@ struct git_push {
|
||||
|
||||
/* options */
|
||||
unsigned pb_parallelism;
|
||||
git_remote_connection_opts connection;
|
||||
git_remote_callbacks callbacks;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -56,22 +56,11 @@ void git_push_status_free(push_status *status);
|
||||
*
|
||||
* @param out New push object
|
||||
* @param remote Remote instance
|
||||
* @param opts Push options or NULL
|
||||
*
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
int git_push_new(git_push **out, git_remote *remote);
|
||||
|
||||
/**
|
||||
* Set options on a push object
|
||||
*
|
||||
* @param push The push object
|
||||
* @param opts The options to set on the push object
|
||||
*
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
int git_push_set_options(
|
||||
git_push *push,
|
||||
const git_push_options *opts);
|
||||
int git_push_new(git_push **out, git_remote *remote, const git_push_options *opts);
|
||||
|
||||
/**
|
||||
* Add a refspec to be pushed
|
||||
@@ -104,11 +93,10 @@ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks);
|
||||
* order to find out which updates were accepted or rejected.
|
||||
*
|
||||
* @param push The push object
|
||||
* @param callbacks the callbacks to use for this connection
|
||||
*
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
int git_push_finish(git_push *push, const git_remote_callbacks *callbacks);
|
||||
int git_push_finish(git_push *push);
|
||||
|
||||
/**
|
||||
* Invoke callback `cb' on each status entry
|
||||
|
||||
@@ -64,10 +64,10 @@ struct git_rebase {
|
||||
git_rebase_t type;
|
||||
char *state_path;
|
||||
|
||||
int head_detached : 1,
|
||||
inmemory : 1,
|
||||
quiet : 1,
|
||||
started : 1;
|
||||
unsigned int head_detached:1,
|
||||
inmemory:1,
|
||||
quiet:1,
|
||||
started:1;
|
||||
|
||||
git_array_t(git_rebase_operation) operations;
|
||||
size_t current;
|
||||
|
||||
439
src/remote.c
439
src/remote.c
@@ -16,6 +16,7 @@
|
||||
#include "refspec.h"
|
||||
#include "fetchhead.h"
|
||||
#include "push.h"
|
||||
#include "proxy.h"
|
||||
|
||||
#include "git2/config.h"
|
||||
#include "git2/types.h"
|
||||
@@ -756,54 +757,200 @@ int git_remote__urlfordirection(
|
||||
return resolve_url(url_out, url, direction, callbacks);
|
||||
}
|
||||
|
||||
static int remote_transport_set_callbacks(git_transport *t, const git_remote_callbacks *cbs)
|
||||
int git_remote_connect_options_init(
|
||||
git_remote_connect_options *opts,
|
||||
unsigned int version)
|
||||
{
|
||||
if (!t->set_callbacks || !cbs)
|
||||
return 0;
|
||||
|
||||
return t->set_callbacks(t, cbs->sideband_progress, NULL,
|
||||
cbs->certificate_check, cbs->payload);
|
||||
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
||||
opts, version, git_remote_connect_options, GIT_REMOTE_CONNECT_OPTIONS_INIT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers)
|
||||
int git_remote_connect_options_dup(
|
||||
git_remote_connect_options *dst,
|
||||
const git_remote_connect_options *src)
|
||||
{
|
||||
if (!t->set_custom_headers)
|
||||
return 0;
|
||||
memcpy(dst, src, sizeof(git_remote_connect_options));
|
||||
|
||||
return t->set_custom_headers(t, custom_headers);
|
||||
if (git_proxy_options_dup(&dst->proxy_opts, &src->proxy_opts) < 0 ||
|
||||
git_strarray_copy(&dst->custom_headers, &src->custom_headers) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn)
|
||||
void git_remote_connect_options_dispose(git_remote_connect_options *opts)
|
||||
{
|
||||
git_transport *t;
|
||||
if (!opts)
|
||||
return;
|
||||
|
||||
git_strarray_dispose(&opts->custom_headers);
|
||||
git_proxy_options_dispose(&opts->proxy_opts);
|
||||
}
|
||||
|
||||
static size_t http_header_name_length(const char *http_header)
|
||||
{
|
||||
const char *colon = strchr(http_header, ':');
|
||||
if (!colon)
|
||||
return 0;
|
||||
return colon - http_header;
|
||||
}
|
||||
|
||||
static bool is_malformed_http_header(const char *http_header)
|
||||
{
|
||||
const char *c;
|
||||
size_t name_len;
|
||||
|
||||
/* Disallow \r and \n */
|
||||
if ((c = strchr(http_header, '\r')) != NULL)
|
||||
return true;
|
||||
if ((c = strchr(http_header, '\n')) != NULL)
|
||||
return true;
|
||||
|
||||
/* Require a header name followed by : */
|
||||
if ((name_len = http_header_name_length(http_header)) < 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static char *forbidden_custom_headers[] = {
|
||||
"User-Agent",
|
||||
"Host",
|
||||
"Accept",
|
||||
"Content-Type",
|
||||
"Transfer-Encoding",
|
||||
"Content-Length",
|
||||
};
|
||||
|
||||
static bool is_forbidden_custom_header(const char *custom_header)
|
||||
{
|
||||
unsigned long i;
|
||||
size_t name_len = http_header_name_length(custom_header);
|
||||
|
||||
/* Disallow headers that we set */
|
||||
for (i = 0; i < ARRAY_SIZE(forbidden_custom_headers); i++)
|
||||
if (strncmp(forbidden_custom_headers[i], custom_header, name_len) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int validate_custom_headers(const git_strarray *custom_headers)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!custom_headers)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < custom_headers->count; i++) {
|
||||
if (is_malformed_http_header(custom_headers->strings[i])) {
|
||||
git_error_set(GIT_ERROR_INVALID, "custom HTTP header '%s' is malformed", custom_headers->strings[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_forbidden_custom_header(custom_headers->strings[i])) {
|
||||
git_error_set(GIT_ERROR_INVALID, "custom HTTP header '%s' is already set by libgit2", custom_headers->strings[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lookup_redirect_config(
|
||||
git_remote_redirect_t *out,
|
||||
git_repository *repo)
|
||||
{
|
||||
git_config *config;
|
||||
const char *value;
|
||||
int bool_value, error = 0;
|
||||
|
||||
if (!repo) {
|
||||
*out = GIT_REMOTE_REDIRECT_INITIAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((error = git_repository_config_snapshot(&config, repo)) < 0)
|
||||
goto done;
|
||||
|
||||
if ((error = git_config_get_string(&value, config, "http.followRedirects")) < 0) {
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
*out = GIT_REMOTE_REDIRECT_INITIAL;
|
||||
error = 0;
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (git_config_parse_bool(&bool_value, value) == 0) {
|
||||
*out = bool_value ? GIT_REMOTE_REDIRECT_ALL :
|
||||
GIT_REMOTE_REDIRECT_NONE;
|
||||
} else if (strcasecmp(value, "initial") == 0) {
|
||||
*out = GIT_REMOTE_REDIRECT_INITIAL;
|
||||
} else {
|
||||
git_error_set(GIT_ERROR_CONFIG, "invalid configuration setting '%s' for 'http.followRedirects'", value);
|
||||
error = -1;
|
||||
}
|
||||
|
||||
done:
|
||||
git_config_free(config);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_remote_connect_options_normalize(
|
||||
git_remote_connect_options *dst,
|
||||
git_repository *repo,
|
||||
const git_remote_connect_options *src)
|
||||
{
|
||||
git_remote_connect_options_dispose(dst);
|
||||
git_remote_connect_options_init(dst, GIT_REMOTE_CONNECT_OPTIONS_VERSION);
|
||||
|
||||
if (src) {
|
||||
GIT_ERROR_CHECK_VERSION(src, GIT_REMOTE_CONNECT_OPTIONS_VERSION, "git_remote_connect_options");
|
||||
GIT_ERROR_CHECK_VERSION(&src->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
|
||||
GIT_ERROR_CHECK_VERSION(&src->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
|
||||
|
||||
if (validate_custom_headers(&src->custom_headers) < 0 ||
|
||||
git_remote_connect_options_dup(dst, src) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dst->follow_redirects == 0) {
|
||||
if (lookup_redirect_config(&dst->follow_redirects, repo) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_remote_connect_ext(
|
||||
git_remote *remote,
|
||||
git_direction direction,
|
||||
const git_remote_connect_options *given_opts)
|
||||
{
|
||||
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
git_str url = GIT_STR_INIT;
|
||||
int flags = GIT_TRANSPORTFLAGS_NONE;
|
||||
git_transport *t;
|
||||
int error;
|
||||
void *payload = NULL;
|
||||
git_credential_acquire_cb credentials = NULL;
|
||||
git_transport_cb transport = NULL;
|
||||
|
||||
GIT_ASSERT_ARG(remote);
|
||||
|
||||
if (callbacks) {
|
||||
GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
|
||||
credentials = callbacks->credentials;
|
||||
transport = callbacks->transport;
|
||||
payload = callbacks->payload;
|
||||
}
|
||||
if (given_opts)
|
||||
memcpy(&opts, given_opts, sizeof(git_remote_connect_options));
|
||||
|
||||
if (conn->proxy)
|
||||
GIT_ERROR_CHECK_VERSION(conn->proxy, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
|
||||
GIT_ERROR_CHECK_VERSION(&opts.callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
|
||||
GIT_ERROR_CHECK_VERSION(&opts.proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
|
||||
|
||||
t = remote->transport;
|
||||
|
||||
if ((error = git_remote__urlfordirection(&url, remote, direction, callbacks)) < 0)
|
||||
if ((error = git_remote__urlfordirection(&url, remote, direction, &opts.callbacks)) < 0)
|
||||
goto on_error;
|
||||
|
||||
/* If we don't have a transport object yet, and the caller specified a
|
||||
* custom transport factory, use that */
|
||||
if (!t && transport &&
|
||||
(error = transport(&t, remote, payload)) < 0)
|
||||
if (!t && opts.callbacks.transport &&
|
||||
(error = opts.callbacks.transport(&t, remote, opts.callbacks.payload)) < 0)
|
||||
goto on_error;
|
||||
|
||||
/* If we still don't have a transport, then use the global
|
||||
@@ -811,11 +958,7 @@ int git_remote__connect(git_remote *remote, git_direction direction, const git_r
|
||||
if (!t && (error = git_transport_new(&t, remote, url.ptr)) < 0)
|
||||
goto on_error;
|
||||
|
||||
if ((error = set_transport_custom_headers(t, conn->custom_headers)) != 0)
|
||||
goto on_error;
|
||||
|
||||
if ((error = remote_transport_set_callbacks(t, callbacks)) < 0 ||
|
||||
(error = t->connect(t, url.ptr, credentials, payload, conn->proxy, direction, flags)) != 0)
|
||||
if ((error = t->connect(t, url.ptr, direction, &opts)) != 0)
|
||||
goto on_error;
|
||||
|
||||
remote->transport = t;
|
||||
@@ -836,14 +979,25 @@ on_error:
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_proxy_options *proxy, const git_strarray *custom_headers)
|
||||
int git_remote_connect(
|
||||
git_remote *remote,
|
||||
git_direction direction,
|
||||
const git_remote_callbacks *callbacks,
|
||||
const git_proxy_options *proxy,
|
||||
const git_strarray *custom_headers)
|
||||
{
|
||||
git_remote_connection_opts conn;
|
||||
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
|
||||
conn.proxy = proxy;
|
||||
conn.custom_headers = custom_headers;
|
||||
if (callbacks)
|
||||
memcpy(&opts.callbacks, callbacks, sizeof(git_remote_callbacks));
|
||||
|
||||
return git_remote__connect(remote, direction, callbacks, &conn);
|
||||
if (proxy)
|
||||
memcpy(&opts.proxy_opts, proxy, sizeof(git_proxy_options));
|
||||
|
||||
if (custom_headers)
|
||||
memcpy(&opts.custom_headers, custom_headers, sizeof(git_strarray));
|
||||
|
||||
return git_remote_connect_ext(remote, direction, &opts);
|
||||
}
|
||||
|
||||
int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
|
||||
@@ -1057,38 +1211,50 @@ static int ls_to_vector(git_vector *out, git_remote *remote)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
|
||||
#define copy_opts(out, in) \
|
||||
if (in) { \
|
||||
(out)->callbacks = (in)->callbacks; \
|
||||
(out)->proxy_opts = (in)->proxy_opts; \
|
||||
(out)->custom_headers = (in)->custom_headers; \
|
||||
(out)->follow_redirects = (in)->follow_redirects; \
|
||||
}
|
||||
|
||||
GIT_INLINE(int) connect_opts_from_fetch_opts(
|
||||
git_remote_connect_options *out,
|
||||
git_remote *remote,
|
||||
const git_fetch_options *fetch_opts)
|
||||
{
|
||||
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
copy_opts(&tmp, fetch_opts);
|
||||
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
|
||||
}
|
||||
|
||||
static int connect_or_reset_options(
|
||||
git_remote *remote,
|
||||
int direction,
|
||||
git_remote_connect_options *opts)
|
||||
{
|
||||
if (!git_remote_connected(remote)) {
|
||||
return git_remote_connect_ext(remote, direction, opts);
|
||||
} else {
|
||||
return remote->transport->set_connect_opts(remote->transport, opts);
|
||||
}
|
||||
}
|
||||
|
||||
/* Download from an already connected remote. */
|
||||
static int git_remote__download(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_fetch_options *opts)
|
||||
{
|
||||
int error = -1;
|
||||
size_t i;
|
||||
git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
|
||||
const git_remote_callbacks *cbs = NULL;
|
||||
const git_strarray *custom_headers = NULL;
|
||||
const git_proxy_options *proxy = NULL;
|
||||
|
||||
GIT_ASSERT_ARG(remote);
|
||||
|
||||
if (!remote->repo) {
|
||||
git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opts) {
|
||||
GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
|
||||
cbs = &opts->callbacks;
|
||||
custom_headers = &opts->custom_headers;
|
||||
GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
|
||||
proxy = &opts->proxy_opts;
|
||||
}
|
||||
|
||||
if (!git_remote_connected(remote) &&
|
||||
(error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, proxy, custom_headers)) < 0)
|
||||
goto on_error;
|
||||
size_t i;
|
||||
int error;
|
||||
|
||||
if (ls_to_vector(&refs, remote) < 0)
|
||||
return -1;
|
||||
|
||||
if ((git_vector_init(&specs, 0, NULL)) < 0)
|
||||
if ((error = git_vector_init(&specs, 0, NULL)) < 0)
|
||||
goto on_error;
|
||||
|
||||
remote->passed_refspecs = 0;
|
||||
@@ -1116,7 +1282,7 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const
|
||||
git_vector_free(&specs);
|
||||
|
||||
if (error < 0)
|
||||
return error;
|
||||
goto on_error;
|
||||
|
||||
if (remote->push) {
|
||||
git_push_free(remote->push);
|
||||
@@ -1124,9 +1290,9 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const
|
||||
}
|
||||
|
||||
if ((error = git_fetch_negotiate(remote, opts)) < 0)
|
||||
return error;
|
||||
goto on_error;
|
||||
|
||||
return git_fetch_download_pack(remote, cbs);
|
||||
error = git_fetch_download_pack(remote);
|
||||
|
||||
on_error:
|
||||
git_vector_free(&refs);
|
||||
@@ -1135,41 +1301,69 @@ on_error:
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_remote_download(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_fetch_options *opts)
|
||||
{
|
||||
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
int error;
|
||||
|
||||
GIT_ASSERT_ARG(remote);
|
||||
|
||||
if (!remote->repo) {
|
||||
git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0)
|
||||
return -1;
|
||||
|
||||
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
|
||||
return error;
|
||||
|
||||
return git_remote__download(remote, refspecs, opts);
|
||||
}
|
||||
|
||||
int git_remote_fetch(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_fetch_options *opts,
|
||||
const char *reflog_message)
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_fetch_options *opts,
|
||||
const char *reflog_message)
|
||||
{
|
||||
int error, update_fetchhead = 1;
|
||||
git_remote_autotag_option_t tagopt = remote->download_tags;
|
||||
bool prune = false;
|
||||
git_str reflog_msg_buf = GIT_STR_INIT;
|
||||
const git_remote_callbacks *cbs = NULL;
|
||||
git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
|
||||
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
|
||||
GIT_ASSERT_ARG(remote);
|
||||
|
||||
if (!remote->repo) {
|
||||
git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0)
|
||||
return -1;
|
||||
|
||||
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
|
||||
return error;
|
||||
|
||||
if (opts) {
|
||||
GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
|
||||
cbs = &opts->callbacks;
|
||||
conn.custom_headers = &opts->custom_headers;
|
||||
update_fetchhead = opts->update_fetchhead;
|
||||
tagopt = opts->download_tags;
|
||||
GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
|
||||
conn.proxy = &opts->proxy_opts;
|
||||
}
|
||||
|
||||
/* Connect and download everything */
|
||||
if ((error = git_remote__connect(remote, GIT_DIRECTION_FETCH, cbs, &conn)) != 0)
|
||||
return error;
|
||||
|
||||
error = git_remote_download(remote, refspecs, opts);
|
||||
error = git_remote__download(remote, refspecs, opts);
|
||||
|
||||
/* We don't need to be connected anymore */
|
||||
git_remote_disconnect(remote);
|
||||
|
||||
/* If the download failed, return the error */
|
||||
if (error != 0)
|
||||
return error;
|
||||
goto done;
|
||||
|
||||
/* Default reflog message */
|
||||
if (reflog_message)
|
||||
@@ -1180,10 +1374,10 @@ int git_remote_fetch(
|
||||
}
|
||||
|
||||
/* Create "remote/foo" branches for all remote branches */
|
||||
error = git_remote_update_tips(remote, cbs, update_fetchhead, tagopt, git_str_cstr(&reflog_msg_buf));
|
||||
error = git_remote_update_tips(remote, &connect_opts.callbacks, update_fetchhead, tagopt, git_str_cstr(&reflog_msg_buf));
|
||||
git_str_dispose(&reflog_msg_buf);
|
||||
if (error < 0)
|
||||
return error;
|
||||
goto done;
|
||||
|
||||
if (opts && opts->prune == GIT_FETCH_PRUNE)
|
||||
prune = true;
|
||||
@@ -1195,8 +1389,10 @@ int git_remote_fetch(
|
||||
prune = remote->prune_refs;
|
||||
|
||||
if (prune)
|
||||
error = git_remote_prune(remote, cbs);
|
||||
error = git_remote_prune(remote, &connect_opts.callbacks);
|
||||
|
||||
done:
|
||||
git_remote_connect_options_dispose(&connect_opts);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -2619,14 +2815,26 @@ done:
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
|
||||
GIT_INLINE(int) connect_opts_from_push_opts(
|
||||
git_remote_connect_options *out,
|
||||
git_remote *remote,
|
||||
const git_push_options *push_opts)
|
||||
{
|
||||
size_t i;
|
||||
int error;
|
||||
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
copy_opts(&tmp, push_opts);
|
||||
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
|
||||
}
|
||||
|
||||
int git_remote_upload(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_push_options *opts)
|
||||
{
|
||||
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
git_push *push;
|
||||
git_refspec *spec;
|
||||
const git_remote_callbacks *cbs = NULL;
|
||||
git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
|
||||
size_t i;
|
||||
int error;
|
||||
|
||||
GIT_ASSERT_ARG(remote);
|
||||
|
||||
@@ -2635,14 +2843,10 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opts) {
|
||||
cbs = &opts->callbacks;
|
||||
conn.custom_headers = &opts->custom_headers;
|
||||
conn.proxy = &opts->proxy_opts;
|
||||
}
|
||||
if ((error = connect_opts_from_push_opts(&connect_opts, remote, opts)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!git_remote_connected(remote) &&
|
||||
(error = git_remote__connect(remote, GIT_DIRECTION_PUSH, cbs, &conn)) < 0)
|
||||
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_PUSH, &connect_opts)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
free_refspecs(&remote->active_refspecs);
|
||||
@@ -2654,14 +2858,11 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
|
||||
remote->push = NULL;
|
||||
}
|
||||
|
||||
if ((error = git_push_new(&remote->push, remote)) < 0)
|
||||
return error;
|
||||
if ((error = git_push_new(&remote->push, remote, opts)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
push = remote->push;
|
||||
|
||||
if (opts && (error = git_push_set_options(push, opts)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (refspecs && refspecs->count > 0) {
|
||||
for (i = 0; i < refspecs->count; i++) {
|
||||
if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
|
||||
@@ -2676,23 +2877,25 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = git_push_finish(push, cbs)) < 0)
|
||||
if ((error = git_push_finish(push)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (cbs && cbs->push_update_reference &&
|
||||
(error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
|
||||
if (connect_opts.callbacks.push_update_reference &&
|
||||
(error = git_push_status_foreach(push, connect_opts.callbacks.push_update_reference, connect_opts.callbacks.payload)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
git_remote_connect_options_dispose(&connect_opts);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
|
||||
int git_remote_push(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
const git_push_options *opts)
|
||||
{
|
||||
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
int error;
|
||||
const git_remote_callbacks *cbs = NULL;
|
||||
const git_strarray *custom_headers = NULL;
|
||||
const git_proxy_options *proxy = NULL;
|
||||
|
||||
GIT_ASSERT_ARG(remote);
|
||||
|
||||
@@ -2701,23 +2904,17 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opts) {
|
||||
GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
|
||||
cbs = &opts->callbacks;
|
||||
custom_headers = &opts->custom_headers;
|
||||
GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
|
||||
proxy = &opts->proxy_opts;
|
||||
}
|
||||
|
||||
if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
|
||||
return error;
|
||||
if (connect_opts_from_push_opts(&connect_opts, remote, opts) < 0)
|
||||
return -1;
|
||||
|
||||
if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
|
||||
return error;
|
||||
goto done;
|
||||
|
||||
error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
|
||||
error = git_remote_update_tips(remote, &connect_opts.callbacks, 0, 0, NULL);
|
||||
|
||||
done:
|
||||
git_remote_disconnect(remote);
|
||||
git_remote_connect_options_dispose(&connect_opts);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
18
src/remote.h
18
src/remote.h
@@ -37,15 +37,6 @@ struct git_remote {
|
||||
int passed_refspecs;
|
||||
};
|
||||
|
||||
typedef struct git_remote_connection_opts {
|
||||
const git_strarray *custom_headers;
|
||||
const git_proxy_options *proxy;
|
||||
} git_remote_connection_opts;
|
||||
|
||||
#define GIT_REMOTE_CONNECTION_OPTIONS_INIT { NULL, NULL }
|
||||
|
||||
int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn);
|
||||
|
||||
int git_remote__urlfordirection(git_str *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks);
|
||||
int git_remote__http_proxy(char **out, git_remote *remote, git_net_url *url);
|
||||
|
||||
@@ -54,4 +45,13 @@ git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *re
|
||||
|
||||
int git_remote__default_branch(git_str *out, git_remote *remote);
|
||||
|
||||
int git_remote_connect_options_dup(
|
||||
git_remote_connect_options *dst,
|
||||
const git_remote_connect_options *src);
|
||||
int git_remote_connect_options_normalize(
|
||||
git_remote_connect_options *dst,
|
||||
git_repository *repo,
|
||||
const git_remote_connect_options *src);
|
||||
void git_remote_connect_options_dispose(git_remote_connect_options *opts);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -336,6 +336,9 @@ int git_status_list_new(
|
||||
GIT_DIFF_FIND_RENAMES_FROM_REWRITES |
|
||||
GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY;
|
||||
|
||||
if (opts != NULL && opts->rename_threshold != 0)
|
||||
findopt.rename_threshold = opts->rename_threshold;
|
||||
|
||||
if (show != GIT_STATUS_SHOW_WORKDIR_ONLY) {
|
||||
if ((error = git_diff_tree_to_index(
|
||||
&status->head2idx, repo, head, index, &diffopt)) < 0)
|
||||
|
||||
@@ -38,7 +38,8 @@ typedef struct {
|
||||
const char *url;
|
||||
const char *request_type;
|
||||
const char *response_type;
|
||||
unsigned chunked : 1;
|
||||
unsigned int initial : 1,
|
||||
chunked : 1;
|
||||
} http_service;
|
||||
|
||||
typedef struct {
|
||||
@@ -70,24 +71,28 @@ static const http_service upload_pack_ls_service = {
|
||||
GIT_HTTP_METHOD_GET, "/info/refs?service=git-upload-pack",
|
||||
NULL,
|
||||
"application/x-git-upload-pack-advertisement",
|
||||
1,
|
||||
0
|
||||
};
|
||||
static const http_service upload_pack_service = {
|
||||
GIT_HTTP_METHOD_POST, "/git-upload-pack",
|
||||
"application/x-git-upload-pack-request",
|
||||
"application/x-git-upload-pack-result",
|
||||
0,
|
||||
0
|
||||
};
|
||||
static const http_service receive_pack_ls_service = {
|
||||
GIT_HTTP_METHOD_GET, "/info/refs?service=git-receive-pack",
|
||||
NULL,
|
||||
"application/x-git-receive-pack-advertisement",
|
||||
1,
|
||||
0
|
||||
};
|
||||
static const http_service receive_pack_service = {
|
||||
GIT_HTTP_METHOD_POST, "/git-receive-pack",
|
||||
"application/x-git-receive-pack-request",
|
||||
"application/x-git-receive-pack-result",
|
||||
0,
|
||||
1
|
||||
};
|
||||
|
||||
@@ -174,6 +179,7 @@ GIT_INLINE(int) handle_remote_auth(
|
||||
git_http_response *response)
|
||||
{
|
||||
http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
|
||||
git_remote_connect_options *connect_opts = &transport->owner->connect_opts;
|
||||
|
||||
if (response->server_auth_credtypes == 0) {
|
||||
git_error_set(GIT_ERROR_HTTP, "server requires authentication that we do not support");
|
||||
@@ -187,8 +193,8 @@ GIT_INLINE(int) handle_remote_auth(
|
||||
transport->owner->url,
|
||||
response->server_auth_schemetypes,
|
||||
response->server_auth_credtypes,
|
||||
transport->owner->cred_acquire_cb,
|
||||
transport->owner->cred_acquire_payload);
|
||||
connect_opts->callbacks.credentials,
|
||||
connect_opts->callbacks.payload);
|
||||
}
|
||||
|
||||
GIT_INLINE(int) handle_proxy_auth(
|
||||
@@ -196,6 +202,7 @@ GIT_INLINE(int) handle_proxy_auth(
|
||||
git_http_response *response)
|
||||
{
|
||||
http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
|
||||
git_remote_connect_options *connect_opts = &transport->owner->connect_opts;
|
||||
|
||||
if (response->proxy_auth_credtypes == 0) {
|
||||
git_error_set(GIT_ERROR_HTTP, "proxy requires authentication that we do not support");
|
||||
@@ -206,13 +213,26 @@ GIT_INLINE(int) handle_proxy_auth(
|
||||
return handle_auth(
|
||||
&transport->proxy,
|
||||
SERVER_TYPE_PROXY,
|
||||
transport->owner->proxy.url,
|
||||
connect_opts->proxy_opts.url,
|
||||
response->server_auth_schemetypes,
|
||||
response->proxy_auth_credtypes,
|
||||
transport->owner->proxy.credentials,
|
||||
transport->owner->proxy.payload);
|
||||
connect_opts->proxy_opts.credentials,
|
||||
connect_opts->proxy_opts.payload);
|
||||
}
|
||||
|
||||
static bool allow_redirect(http_stream *stream)
|
||||
{
|
||||
http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
|
||||
|
||||
switch (transport->owner->connect_opts.follow_redirects) {
|
||||
case GIT_REMOTE_REDIRECT_INITIAL:
|
||||
return (stream->service->initial == 1);
|
||||
case GIT_REMOTE_REDIRECT_ALL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_response(
|
||||
bool *complete,
|
||||
@@ -231,7 +251,7 @@ static int handle_response(
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (git_net_url_apply_redirect(&transport->server.url, response->location, stream->service->url) < 0) {
|
||||
if (git_net_url_apply_redirect(&transport->server.url, response->location, allow_redirect(stream), stream->service->url) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -286,6 +306,7 @@ static int lookup_proxy(
|
||||
bool *out_use,
|
||||
http_subtransport *transport)
|
||||
{
|
||||
git_remote_connect_options *connect_opts = &transport->owner->connect_opts;
|
||||
const char *proxy;
|
||||
git_remote *remote;
|
||||
char *config = NULL;
|
||||
@@ -294,9 +315,9 @@ static int lookup_proxy(
|
||||
*out_use = false;
|
||||
git_net_url_dispose(&transport->proxy.url);
|
||||
|
||||
switch (transport->owner->proxy.type) {
|
||||
switch (connect_opts->proxy_opts.type) {
|
||||
case GIT_PROXY_SPECIFIED:
|
||||
proxy = transport->owner->proxy.url;
|
||||
proxy = connect_opts->proxy_opts.url;
|
||||
break;
|
||||
|
||||
case GIT_PROXY_AUTO:
|
||||
@@ -345,7 +366,7 @@ static int generate_request(
|
||||
request->credentials = transport->server.cred;
|
||||
request->proxy = use_proxy ? &transport->proxy.url : NULL;
|
||||
request->proxy_credentials = transport->proxy.cred;
|
||||
request->custom_headers = &transport->owner->custom_headers;
|
||||
request->custom_headers = &transport->owner->connect_opts.custom_headers;
|
||||
|
||||
if (stream->service->method == GIT_HTTP_METHOD_POST) {
|
||||
request->chunked = stream->service->chunked;
|
||||
@@ -633,6 +654,7 @@ static int http_action(
|
||||
git_smart_service_t action)
|
||||
{
|
||||
http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent);
|
||||
git_remote_connect_options *connect_opts = &transport->owner->connect_opts;
|
||||
http_stream *stream;
|
||||
const http_service *service;
|
||||
int error;
|
||||
@@ -664,10 +686,10 @@ static int http_action(
|
||||
if (!transport->http_client) {
|
||||
git_http_client_options opts = {0};
|
||||
|
||||
opts.server_certificate_check_cb = transport->owner->certificate_check_cb;
|
||||
opts.server_certificate_check_payload = transport->owner->message_cb_payload;
|
||||
opts.proxy_certificate_check_cb = transport->owner->proxy.certificate_check;
|
||||
opts.proxy_certificate_check_payload = transport->owner->proxy.payload;
|
||||
opts.server_certificate_check_cb = connect_opts->callbacks.certificate_check;
|
||||
opts.server_certificate_check_payload = connect_opts->callbacks.payload;
|
||||
opts.proxy_certificate_check_cb = connect_opts->proxy_opts.certificate_check;
|
||||
opts.proxy_certificate_check_payload = connect_opts->proxy_opts.payload;
|
||||
|
||||
if (git_http_client_new(&transport->http_client, &opts) < 0)
|
||||
return -1;
|
||||
|
||||
@@ -34,12 +34,9 @@ typedef struct {
|
||||
git_remote *owner;
|
||||
char *url;
|
||||
int direction;
|
||||
int flags;
|
||||
git_atomic32 cancelled;
|
||||
git_repository *repo;
|
||||
git_transport_message_cb progress_cb;
|
||||
git_transport_message_cb error_cb;
|
||||
void *message_cb_payload;
|
||||
git_remote_connect_options connect_opts;
|
||||
git_vector refs;
|
||||
unsigned connected : 1,
|
||||
have_refs : 1;
|
||||
@@ -200,30 +197,26 @@ on_error:
|
||||
static int local_connect(
|
||||
git_transport *transport,
|
||||
const char *url,
|
||||
git_credential_acquire_cb cred_acquire_cb,
|
||||
void *cred_acquire_payload,
|
||||
const git_proxy_options *proxy,
|
||||
int direction, int flags)
|
||||
int direction,
|
||||
const git_remote_connect_options *connect_opts)
|
||||
{
|
||||
git_repository *repo;
|
||||
int error;
|
||||
transport_local *t = (transport_local *) transport;
|
||||
transport_local *t = (transport_local *)transport;
|
||||
const char *path;
|
||||
git_str buf = GIT_STR_INIT;
|
||||
|
||||
GIT_UNUSED(cred_acquire_cb);
|
||||
GIT_UNUSED(cred_acquire_payload);
|
||||
GIT_UNUSED(proxy);
|
||||
|
||||
if (t->connected)
|
||||
return 0;
|
||||
|
||||
if (git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, connect_opts) < 0)
|
||||
return -1;
|
||||
|
||||
free_heads(&t->refs);
|
||||
|
||||
t->url = git__strdup(url);
|
||||
GIT_ERROR_CHECK_ALLOC(t->url);
|
||||
t->direction = direction;
|
||||
t->flags = flags;
|
||||
|
||||
/* 'url' may be a url or path; convert to a path */
|
||||
if ((error = git_fs_path_from_url_or_path(&buf, url)) < 0) {
|
||||
@@ -249,6 +242,20 @@ static int local_connect(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int local_set_connect_opts(
|
||||
git_transport *transport,
|
||||
const git_remote_connect_options *connect_opts)
|
||||
{
|
||||
transport_local *t = (transport_local *)transport;
|
||||
|
||||
if (!t->connected) {
|
||||
git_error_set(GIT_ERROR_NET, "cannot reconfigure a transport that is not connected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, connect_opts);
|
||||
}
|
||||
|
||||
static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport)
|
||||
{
|
||||
transport_local *t = (transport_local *)transport;
|
||||
@@ -337,10 +344,10 @@ static int transfer_to_push_transfer(const git_indexer_progress *stats, void *pa
|
||||
|
||||
static int local_push(
|
||||
git_transport *transport,
|
||||
git_push *push,
|
||||
const git_remote_callbacks *cbs)
|
||||
git_push *push)
|
||||
{
|
||||
transport_local *t = (transport_local *)transport;
|
||||
git_remote_callbacks *cbs = &t->connect_opts.callbacks;
|
||||
git_repository *remote_repo = NULL;
|
||||
push_spec *spec;
|
||||
char *url = NULL;
|
||||
@@ -349,8 +356,6 @@ static int local_push(
|
||||
int error;
|
||||
size_t j;
|
||||
|
||||
GIT_UNUSED(cbs);
|
||||
|
||||
/* 'push->remote->url' may be a url or path; convert to a path */
|
||||
if ((error = git_fs_path_from_url_or_path(&buf, push->remote->url)) < 0) {
|
||||
git_str_dispose(&buf);
|
||||
@@ -440,12 +445,11 @@ static int local_push(
|
||||
}
|
||||
|
||||
if (push->specs.length) {
|
||||
int flags = t->flags;
|
||||
url = git__strdup(t->url);
|
||||
|
||||
if (!url || t->parent.close(&t->parent) < 0 ||
|
||||
t->parent.connect(&t->parent, url,
|
||||
NULL, NULL, NULL, GIT_DIRECTION_PUSH, flags))
|
||||
GIT_DIRECTION_PUSH, NULL))
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
@@ -482,7 +486,7 @@ static int local_counting(int stage, unsigned int current, unsigned int total, v
|
||||
transport_local *t = payload;
|
||||
int error;
|
||||
|
||||
if (!t->progress_cb)
|
||||
if (!t->connect_opts.callbacks.sideband_progress)
|
||||
return 0;
|
||||
|
||||
if (stage == GIT_PACKBUILDER_ADDING_OBJECTS) {
|
||||
@@ -500,9 +504,19 @@ static int local_counting(int stage, unsigned int current, unsigned int total, v
|
||||
if (git_str_oom(&progress_info))
|
||||
return -1;
|
||||
|
||||
error = t->progress_cb(git_str_cstr(&progress_info), (int)git_str_len(&progress_info), t->message_cb_payload);
|
||||
git_str_dispose(&progress_info);
|
||||
if (progress_info.size > INT_MAX) {
|
||||
git_error_set(GIT_ERROR_NET, "remote sent overly large progress data");
|
||||
git_str_dispose(&progress_info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
error = t->connect_opts.callbacks.sideband_progress(
|
||||
progress_info.ptr,
|
||||
(int)progress_info.size,
|
||||
t->connect_opts.callbacks.payload);
|
||||
|
||||
git_str_dispose(&progress_info);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -532,9 +546,7 @@ static int foreach_reference_cb(git_reference *reference, void *payload)
|
||||
static int local_download_pack(
|
||||
git_transport *transport,
|
||||
git_repository *repo,
|
||||
git_indexer_progress *stats,
|
||||
git_indexer_progress_cb progress_cb,
|
||||
void *progress_payload)
|
||||
git_indexer_progress *stats)
|
||||
{
|
||||
transport_local *t = (transport_local*)transport;
|
||||
git_revwalk *walk = NULL;
|
||||
@@ -545,9 +557,11 @@ static int local_download_pack(
|
||||
git_odb_writepack *writepack = NULL;
|
||||
git_odb *odb = NULL;
|
||||
git_str progress_info = GIT_STR_INIT;
|
||||
foreach_data data = {0};
|
||||
|
||||
if ((error = git_revwalk_new(&walk, t->repo)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
git_revwalk_sorting(walk, GIT_SORT_TIME);
|
||||
|
||||
if ((error = git_packbuilder_new(&pack, t->repo)) < 0)
|
||||
@@ -583,44 +597,56 @@ static int local_download_pack(
|
||||
if ((error = git_packbuilder_insert_walk(pack, walk)))
|
||||
goto cleanup;
|
||||
|
||||
if ((error = git_str_printf(&progress_info, counting_objects_fmt, git_packbuilder_object_count(pack))) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (t->progress_cb &&
|
||||
(error = t->progress_cb(git_str_cstr(&progress_info), (int)git_str_len(&progress_info), t->message_cb_payload)) < 0)
|
||||
goto cleanup;
|
||||
if (t->connect_opts.callbacks.sideband_progress) {
|
||||
if ((error = git_str_printf(
|
||||
&progress_info,
|
||||
counting_objects_fmt,
|
||||
git_packbuilder_object_count(pack))) < 0 ||
|
||||
(error = t->connect_opts.callbacks.sideband_progress(
|
||||
progress_info.ptr,
|
||||
(int)progress_info.size,
|
||||
t->connect_opts.callbacks.payload)) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Walk the objects, building a packfile */
|
||||
if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* One last one with the newline */
|
||||
git_str_clear(&progress_info);
|
||||
git_str_printf(&progress_info, counting_objects_fmt, git_packbuilder_object_count(pack));
|
||||
if ((error = git_str_putc(&progress_info, '\n')) < 0)
|
||||
goto cleanup;
|
||||
if (t->connect_opts.callbacks.sideband_progress) {
|
||||
git_str_clear(&progress_info);
|
||||
|
||||
if (t->progress_cb &&
|
||||
(error = t->progress_cb(git_str_cstr(&progress_info), (int)git_str_len(&progress_info), t->message_cb_payload)) < 0)
|
||||
goto cleanup;
|
||||
if ((error = git_str_printf(
|
||||
&progress_info,
|
||||
counting_objects_fmt,
|
||||
git_packbuilder_object_count(pack))) < 0 ||
|
||||
(error = git_str_putc(&progress_info, '\n')) < 0 ||
|
||||
(error = t->connect_opts.callbacks.sideband_progress(
|
||||
progress_info.ptr,
|
||||
(int)progress_info.size,
|
||||
t->connect_opts.callbacks.payload)) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) != 0)
|
||||
if ((error = git_odb_write_pack(
|
||||
&writepack,
|
||||
odb,
|
||||
t->connect_opts.callbacks.transfer_progress,
|
||||
t->connect_opts.callbacks.payload)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Write the data to the ODB */
|
||||
{
|
||||
foreach_data data = {0};
|
||||
data.stats = stats;
|
||||
data.progress_cb = progress_cb;
|
||||
data.progress_payload = progress_payload;
|
||||
data.writepack = writepack;
|
||||
data.stats = stats;
|
||||
data.progress_cb = t->connect_opts.callbacks.transfer_progress;
|
||||
data.progress_payload = t->connect_opts.callbacks.payload;
|
||||
data.writepack = writepack;
|
||||
|
||||
/* autodetect */
|
||||
git_packbuilder_set_threads(pack, 0);
|
||||
/* autodetect */
|
||||
git_packbuilder_set_threads(pack, 0);
|
||||
|
||||
if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) != 0)
|
||||
goto cleanup;
|
||||
}
|
||||
if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) != 0)
|
||||
goto cleanup;
|
||||
|
||||
error = writepack->commit(writepack, stats);
|
||||
|
||||
@@ -632,24 +658,6 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int local_set_callbacks(
|
||||
git_transport *transport,
|
||||
git_transport_message_cb progress_cb,
|
||||
git_transport_message_cb error_cb,
|
||||
git_transport_certificate_check_cb certificate_check_cb,
|
||||
void *message_cb_payload)
|
||||
{
|
||||
transport_local *t = (transport_local *)transport;
|
||||
|
||||
GIT_UNUSED(certificate_check_cb);
|
||||
|
||||
t->progress_cb = progress_cb;
|
||||
t->error_cb = error_cb;
|
||||
t->message_cb_payload = message_cb_payload;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int local_is_connected(git_transport *transport)
|
||||
{
|
||||
transport_local *t = (transport_local *)transport;
|
||||
@@ -657,15 +665,6 @@ static int local_is_connected(git_transport *transport)
|
||||
return t->connected;
|
||||
}
|
||||
|
||||
static int local_read_flags(git_transport *transport, int *flags)
|
||||
{
|
||||
transport_local *t = (transport_local *)transport;
|
||||
|
||||
*flags = t->flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void local_cancel(git_transport *transport)
|
||||
{
|
||||
transport_local *t = (transport_local *)transport;
|
||||
@@ -720,8 +719,8 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param)
|
||||
GIT_ERROR_CHECK_ALLOC(t);
|
||||
|
||||
t->parent.version = GIT_TRANSPORT_VERSION;
|
||||
t->parent.set_callbacks = local_set_callbacks;
|
||||
t->parent.connect = local_connect;
|
||||
t->parent.set_connect_opts = local_set_connect_opts;
|
||||
t->parent.negotiate_fetch = local_negotiate_fetch;
|
||||
t->parent.download_pack = local_download_pack;
|
||||
t->parent.push = local_push;
|
||||
@@ -729,7 +728,6 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param)
|
||||
t->parent.free = local_free;
|
||||
t->parent.ls = local_ls;
|
||||
t->parent.is_connected = local_is_connected;
|
||||
t->parent.read_flags = local_read_flags;
|
||||
t->parent.cancel = local_cancel;
|
||||
|
||||
if ((error = git_vector_init(&t->refs, 0, NULL)) < 0) {
|
||||
|
||||
@@ -56,101 +56,6 @@ GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransp
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int git_smart__set_callbacks(
|
||||
git_transport *transport,
|
||||
git_transport_message_cb progress_cb,
|
||||
git_transport_message_cb error_cb,
|
||||
git_transport_certificate_check_cb certificate_check_cb,
|
||||
void *message_cb_payload)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
|
||||
t->progress_cb = progress_cb;
|
||||
t->error_cb = error_cb;
|
||||
t->certificate_check_cb = certificate_check_cb;
|
||||
t->message_cb_payload = message_cb_payload;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t http_header_name_length(const char *http_header)
|
||||
{
|
||||
const char *colon = strchr(http_header, ':');
|
||||
if (!colon)
|
||||
return 0;
|
||||
return colon - http_header;
|
||||
}
|
||||
|
||||
static bool is_malformed_http_header(const char *http_header)
|
||||
{
|
||||
const char *c;
|
||||
size_t name_len;
|
||||
|
||||
/* Disallow \r and \n */
|
||||
c = strchr(http_header, '\r');
|
||||
if (c)
|
||||
return true;
|
||||
c = strchr(http_header, '\n');
|
||||
if (c)
|
||||
return true;
|
||||
|
||||
/* Require a header name followed by : */
|
||||
name_len = http_header_name_length(http_header);
|
||||
if (name_len < 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static char *forbidden_custom_headers[] = {
|
||||
"User-Agent",
|
||||
"Host",
|
||||
"Accept",
|
||||
"Content-Type",
|
||||
"Transfer-Encoding",
|
||||
"Content-Length",
|
||||
};
|
||||
|
||||
static bool is_forbidden_custom_header(const char *custom_header)
|
||||
{
|
||||
unsigned long i;
|
||||
size_t name_len = http_header_name_length(custom_header);
|
||||
|
||||
/* Disallow headers that we set */
|
||||
for (i = 0; i < ARRAY_SIZE(forbidden_custom_headers); i++)
|
||||
if (strncmp(forbidden_custom_headers[i], custom_header, name_len) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int git_smart__set_custom_headers(
|
||||
git_transport *transport,
|
||||
const git_strarray *custom_headers)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
size_t i;
|
||||
|
||||
if (t->custom_headers.count)
|
||||
git_strarray_dispose(&t->custom_headers);
|
||||
|
||||
if (!custom_headers)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < custom_headers->count; i++) {
|
||||
if (is_malformed_http_header(custom_headers->strings[i])) {
|
||||
git_error_set(GIT_ERROR_INVALID, "custom HTTP header '%s' is malformed", custom_headers->strings[i]);
|
||||
return -1;
|
||||
}
|
||||
if (is_forbidden_custom_header(custom_headers->strings[i])) {
|
||||
git_error_set(GIT_ERROR_INVALID, "custom HTTP header '%s' is already set by libgit2", custom_headers->strings[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return git_strarray_copy(&t->custom_headers, custom_headers);
|
||||
}
|
||||
|
||||
int git_smart__update_heads(transport_smart *t, git_vector *symrefs)
|
||||
{
|
||||
size_t i;
|
||||
@@ -206,11 +111,8 @@ static void free_symrefs(git_vector *symrefs)
|
||||
static int git_smart__connect(
|
||||
git_transport *transport,
|
||||
const char *url,
|
||||
git_credential_acquire_cb cred_acquire_cb,
|
||||
void *cred_acquire_payload,
|
||||
const git_proxy_options *proxy,
|
||||
int direction,
|
||||
int flags)
|
||||
const git_remote_connect_options *connect_opts)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
git_smart_subtransport_stream *stream;
|
||||
@@ -223,24 +125,19 @@ static int git_smart__connect(
|
||||
if (git_smart__reset_stream(t, true) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, connect_opts) < 0)
|
||||
return -1;
|
||||
|
||||
t->url = git__strdup(url);
|
||||
GIT_ERROR_CHECK_ALLOC(t->url);
|
||||
|
||||
git_proxy_options_clear(&t->proxy);
|
||||
|
||||
if (git_proxy_options_dup(&t->proxy, proxy) < 0)
|
||||
return -1;
|
||||
|
||||
t->direction = direction;
|
||||
t->flags = flags;
|
||||
t->cred_acquire_cb = cred_acquire_cb;
|
||||
t->cred_acquire_payload = cred_acquire_payload;
|
||||
|
||||
if (GIT_DIRECTION_FETCH == t->direction)
|
||||
if (GIT_DIRECTION_FETCH == t->direction) {
|
||||
service = GIT_SERVICE_UPLOADPACK_LS;
|
||||
else if (GIT_DIRECTION_PUSH == t->direction)
|
||||
} else if (GIT_DIRECTION_PUSH == t->direction) {
|
||||
service = GIT_SERVICE_RECEIVEPACK_LS;
|
||||
else {
|
||||
} else {
|
||||
git_error_set(GIT_ERROR_NET, "invalid direction");
|
||||
return -1;
|
||||
}
|
||||
@@ -315,6 +212,20 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int git_smart__set_connect_opts(
|
||||
git_transport *transport,
|
||||
const git_remote_connect_options *opts)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
|
||||
if (!t->connected) {
|
||||
git_error_set(GIT_ERROR_NET, "cannot reconfigure a transport that is not connected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return git_remote_connect_options_normalize(&t->connect_opts, t->owner->repo, opts);
|
||||
}
|
||||
|
||||
static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
@@ -401,15 +312,6 @@ static int git_smart__is_connected(git_transport *transport)
|
||||
return t->connected;
|
||||
}
|
||||
|
||||
static int git_smart__read_flags(git_transport *transport, int *flags)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
|
||||
*flags = t->flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int git_smart__close(git_transport *transport)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
@@ -465,9 +367,8 @@ static void git_smart__free(git_transport *transport)
|
||||
git_pkt_free(p);
|
||||
|
||||
git_vector_free(refs);
|
||||
git__free((char *)t->proxy.url);
|
||||
|
||||
git_strarray_dispose(&t->custom_headers);
|
||||
git_remote_connect_options_dispose(&t->connect_opts);
|
||||
|
||||
git__free(t);
|
||||
}
|
||||
@@ -482,34 +383,30 @@ static int ref_name_cmp(const void *a, const void *b)
|
||||
int git_transport_smart_certificate_check(git_transport *transport, git_cert *cert, int valid, const char *hostname)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
git_remote_connect_options *connect_opts = &t->connect_opts;
|
||||
|
||||
GIT_ASSERT_ARG(transport);
|
||||
GIT_ASSERT_ARG(cert);
|
||||
GIT_ASSERT_ARG(hostname);
|
||||
|
||||
if (!t->certificate_check_cb)
|
||||
if (!connect_opts->callbacks.certificate_check)
|
||||
return GIT_PASSTHROUGH;
|
||||
|
||||
return t->certificate_check_cb(cert, valid, hostname, t->message_cb_payload);
|
||||
return connect_opts->callbacks.certificate_check(cert, valid, hostname, connect_opts->callbacks.payload);
|
||||
}
|
||||
|
||||
int git_transport_smart_credentials(git_credential **out, git_transport *transport, const char *user, int methods)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
git_remote_connect_options *connect_opts = &t->connect_opts;
|
||||
|
||||
GIT_ASSERT_ARG(out);
|
||||
GIT_ASSERT_ARG(transport);
|
||||
|
||||
if (!t->cred_acquire_cb)
|
||||
if (!connect_opts->callbacks.credentials)
|
||||
return GIT_PASSTHROUGH;
|
||||
|
||||
return t->cred_acquire_cb(out, t->url, user, methods, t->cred_acquire_payload);
|
||||
}
|
||||
|
||||
int git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
return git_proxy_options_dup(out, &t->proxy);
|
||||
return connect_opts->callbacks.credentials(out, t->url, user, methods, connect_opts->callbacks.payload);
|
||||
}
|
||||
|
||||
int git_transport_smart(git_transport **out, git_remote *owner, void *param)
|
||||
@@ -524,9 +421,8 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
|
||||
GIT_ERROR_CHECK_ALLOC(t);
|
||||
|
||||
t->parent.version = GIT_TRANSPORT_VERSION;
|
||||
t->parent.set_callbacks = git_smart__set_callbacks;
|
||||
t->parent.set_custom_headers = git_smart__set_custom_headers;
|
||||
t->parent.connect = git_smart__connect;
|
||||
t->parent.set_connect_opts = git_smart__set_connect_opts;
|
||||
t->parent.close = git_smart__close;
|
||||
t->parent.free = git_smart__free;
|
||||
t->parent.negotiate_fetch = git_smart__negotiate_fetch;
|
||||
@@ -534,7 +430,6 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
|
||||
t->parent.push = git_smart__push;
|
||||
t->parent.ls = git_smart__ls;
|
||||
t->parent.is_connected = git_smart__is_connected;
|
||||
t->parent.read_flags = git_smart__read_flags;
|
||||
t->parent.cancel = git_smart__cancel;
|
||||
|
||||
t->owner = owner;
|
||||
|
||||
@@ -119,16 +119,16 @@ typedef struct {
|
||||
} git_pkt_unpack;
|
||||
|
||||
typedef struct transport_smart_caps {
|
||||
int common:1,
|
||||
ofs_delta:1,
|
||||
multi_ack: 1,
|
||||
multi_ack_detailed: 1,
|
||||
side_band:1,
|
||||
side_band_64k:1,
|
||||
include_tag:1,
|
||||
delete_refs:1,
|
||||
report_status:1,
|
||||
thin_pack:1;
|
||||
unsigned int common:1,
|
||||
ofs_delta:1,
|
||||
multi_ack:1,
|
||||
multi_ack_detailed:1,
|
||||
side_band:1,
|
||||
side_band_64k:1,
|
||||
include_tag:1,
|
||||
delete_refs:1,
|
||||
report_status:1,
|
||||
thin_pack:1;
|
||||
} transport_smart_caps;
|
||||
|
||||
typedef int (*packetsize_cb)(size_t received, void *payload);
|
||||
@@ -137,16 +137,8 @@ typedef struct {
|
||||
git_transport parent;
|
||||
git_remote *owner;
|
||||
char *url;
|
||||
git_credential_acquire_cb cred_acquire_cb;
|
||||
void *cred_acquire_payload;
|
||||
git_proxy_options proxy;
|
||||
git_remote_connect_options connect_opts;
|
||||
int direction;
|
||||
int flags;
|
||||
git_transport_message_cb progress_cb;
|
||||
git_transport_message_cb error_cb;
|
||||
git_transport_certificate_check_cb certificate_check_cb;
|
||||
void *message_cb_payload;
|
||||
git_strarray custom_headers;
|
||||
git_smart_subtransport *wrapped;
|
||||
git_smart_subtransport_stream *current_stream;
|
||||
transport_smart_caps caps;
|
||||
@@ -157,8 +149,8 @@ typedef struct {
|
||||
packetsize_cb packetsize_cb;
|
||||
void *packetsize_payload;
|
||||
unsigned rpc : 1,
|
||||
have_refs : 1,
|
||||
connected : 1;
|
||||
have_refs : 1,
|
||||
connected : 1;
|
||||
gitno_buffer buffer;
|
||||
char buffer_data[65536];
|
||||
} transport_smart;
|
||||
@@ -166,7 +158,7 @@ typedef struct {
|
||||
/* smart_protocol.c */
|
||||
int git_smart__store_refs(transport_smart *t, int flushes);
|
||||
int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vector *symrefs);
|
||||
int git_smart__push(git_transport *transport, git_push *push, const git_remote_callbacks *cbs);
|
||||
int git_smart__push(git_transport *transport, git_push *push);
|
||||
|
||||
int git_smart__negotiate_fetch(
|
||||
git_transport *transport,
|
||||
@@ -177,9 +169,7 @@ int git_smart__negotiate_fetch(
|
||||
int git_smart__download_pack(
|
||||
git_transport *transport,
|
||||
git_repository *repo,
|
||||
git_indexer_progress *stats,
|
||||
git_indexer_progress_cb progress_cb,
|
||||
void *progress_payload);
|
||||
git_indexer_progress *stats);
|
||||
|
||||
/* smart.c */
|
||||
int git_smart__negotiation_step(git_transport *transport, void *data, size_t len);
|
||||
|
||||
@@ -512,9 +512,7 @@ static int network_packetsize(size_t received, void *payload)
|
||||
int git_smart__download_pack(
|
||||
git_transport *transport,
|
||||
git_repository *repo,
|
||||
git_indexer_progress *stats,
|
||||
git_indexer_progress_cb progress_cb,
|
||||
void *progress_payload)
|
||||
git_indexer_progress *stats)
|
||||
{
|
||||
transport_smart *t = (transport_smart *)transport;
|
||||
gitno_buffer *buf = &t->buffer;
|
||||
@@ -523,6 +521,10 @@ int git_smart__download_pack(
|
||||
int error = 0;
|
||||
struct network_packetsize_payload npp = {0};
|
||||
|
||||
// TODO
|
||||
git_indexer_progress_cb progress_cb = t->connect_opts.callbacks.transfer_progress;
|
||||
void *progress_payload = t->connect_opts.callbacks.payload;
|
||||
|
||||
memset(stats, 0, sizeof(git_indexer_progress));
|
||||
|
||||
if (progress_cb) {
|
||||
@@ -568,7 +570,7 @@ int git_smart__download_pack(
|
||||
git_error_clear();
|
||||
error = GIT_EUSER;
|
||||
} else if (pkt->type == GIT_PKT_PROGRESS) {
|
||||
if (t->progress_cb) {
|
||||
if (t->connect_opts.callbacks.sideband_progress) {
|
||||
git_pkt_progress *p = (git_pkt_progress *) pkt;
|
||||
|
||||
if (p->len > INT_MAX) {
|
||||
@@ -577,7 +579,7 @@ int git_smart__download_pack(
|
||||
goto done;
|
||||
}
|
||||
|
||||
error = t->progress_cb(p->data, (int)p->len, t->message_cb_payload);
|
||||
error = t->connect_opts.callbacks.sideband_progress(p->data, (int)p->len, t->connect_opts.callbacks.payload);
|
||||
}
|
||||
} else if (pkt->type == GIT_PKT_DATA) {
|
||||
git_pkt_data *p = (git_pkt_data *) pkt;
|
||||
@@ -811,7 +813,7 @@ static int parse_report(transport_smart *transport, git_push *push)
|
||||
error = -1;
|
||||
break;
|
||||
case GIT_PKT_PROGRESS:
|
||||
if (transport->progress_cb) {
|
||||
if (transport->connect_opts.callbacks.sideband_progress) {
|
||||
git_pkt_progress *p = (git_pkt_progress *) pkt;
|
||||
|
||||
if (p->len > INT_MAX) {
|
||||
@@ -820,7 +822,7 @@ static int parse_report(transport_smart *transport, git_push *push)
|
||||
goto done;
|
||||
}
|
||||
|
||||
error = transport->progress_cb(p->data, (int)p->len, transport->message_cb_payload);
|
||||
error = transport->connect_opts.callbacks.sideband_progress(p->data, (int)p->len, transport->connect_opts.callbacks.payload);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -987,9 +989,10 @@ static int stream_thunk(void *buf, size_t size, void *data)
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_smart__push(git_transport *transport, git_push *push, const git_remote_callbacks *cbs)
|
||||
int git_smart__push(git_transport *transport, git_push *push)
|
||||
{
|
||||
transport_smart *t = (transport_smart *)transport;
|
||||
git_remote_callbacks *cbs = &t->connect_opts.callbacks;
|
||||
struct push_packbuilder_payload packbuilder_payload = {0};
|
||||
git_str pktline = GIT_STR_INIT;
|
||||
int error = 0, need_pack = 0;
|
||||
|
||||
@@ -441,11 +441,15 @@ static int request_creds(git_credential **out, ssh_subtransport *t, const char *
|
||||
int error, no_callback = 0;
|
||||
git_credential *cred = NULL;
|
||||
|
||||
if (!t->owner->cred_acquire_cb) {
|
||||
if (!t->owner->connect_opts.callbacks.credentials) {
|
||||
no_callback = 1;
|
||||
} else {
|
||||
error = t->owner->cred_acquire_cb(&cred, t->owner->url, user, auth_methods,
|
||||
t->owner->cred_acquire_payload);
|
||||
error = t->owner->connect_opts.callbacks.credentials(
|
||||
&cred,
|
||||
t->owner->url,
|
||||
user,
|
||||
auth_methods,
|
||||
t->owner->connect_opts.callbacks.payload);
|
||||
|
||||
if (error == GIT_PASSTHROUGH) {
|
||||
no_callback = 1;
|
||||
@@ -558,7 +562,7 @@ post_extract:
|
||||
if ((error = _git_ssh_session_create(&session, s->io)) < 0)
|
||||
goto done;
|
||||
|
||||
if (t->owner->certificate_check_cb != NULL) {
|
||||
if (t->owner->connect_opts.callbacks.certificate_check != NULL) {
|
||||
git_cert_hostkey cert = {{ 0 }}, *cert_ptr;
|
||||
const char *key;
|
||||
size_t cert_len;
|
||||
@@ -632,7 +636,11 @@ post_extract:
|
||||
|
||||
cert_ptr = &cert;
|
||||
|
||||
error = t->owner->certificate_check_cb((git_cert *) cert_ptr, 0, urldata.host, t->owner->message_cb_payload);
|
||||
error = t->owner->connect_opts.callbacks.certificate_check(
|
||||
(git_cert *)cert_ptr,
|
||||
0,
|
||||
urldata.host,
|
||||
t->owner->connect_opts.callbacks.payload);
|
||||
|
||||
if (error < 0 && error != GIT_PASSTHROUGH) {
|
||||
if (!git_error_last())
|
||||
|
||||
@@ -293,14 +293,14 @@ static int certificate_check(winhttp_stream *s, int valid)
|
||||
git_cert_x509 cert;
|
||||
|
||||
/* If there is no override, we should fail if WinHTTP doesn't think it's fine */
|
||||
if (t->owner->certificate_check_cb == NULL && !valid) {
|
||||
if (t->owner->connect_opts.callbacks.certificate_check == NULL && !valid) {
|
||||
if (!git_error_last())
|
||||
git_error_set(GIT_ERROR_HTTP, "unknown certificate check failure");
|
||||
|
||||
return GIT_ECERTIFICATE;
|
||||
}
|
||||
|
||||
if (t->owner->certificate_check_cb == NULL || git__strcmp(t->server.url.scheme, "https") != 0)
|
||||
if (t->owner->connect_opts.callbacks.certificate_check == NULL || git__strcmp(t->server.url.scheme, "https") != 0)
|
||||
return 0;
|
||||
|
||||
if (!WinHttpQueryOption(s->request, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert_ctx, &cert_ctx_size)) {
|
||||
@@ -312,7 +312,7 @@ static int certificate_check(winhttp_stream *s, int valid)
|
||||
cert.parent.cert_type = GIT_CERT_X509;
|
||||
cert.data = cert_ctx->pbCertEncoded;
|
||||
cert.len = cert_ctx->cbCertEncoded;
|
||||
error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->server.url.host, t->owner->message_cb_payload);
|
||||
error = t->owner->connect_opts.callbacks.certificate_check((git_cert *) &cert, valid, t->server.url.host, t->owner->connect_opts.callbacks.payload);
|
||||
CertFreeCertificateContext(cert_ctx);
|
||||
|
||||
if (error == GIT_PASSTHROUGH)
|
||||
@@ -426,7 +426,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
proxy_opts = &t->owner->proxy;
|
||||
proxy_opts = &t->owner->connect_opts.proxy_opts;
|
||||
if (proxy_opts->type == GIT_PROXY_AUTO) {
|
||||
/* Set proxy if necessary */
|
||||
if (git_remote__http_proxy(&proxy_url, t->owner->owner, &t->server.url) < 0)
|
||||
@@ -560,10 +560,10 @@ static int winhttp_stream_connect(winhttp_stream *s)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < t->owner->custom_headers.count; i++) {
|
||||
if (t->owner->custom_headers.strings[i]) {
|
||||
for (i = 0; i < t->owner->connect_opts.custom_headers.count; i++) {
|
||||
if (t->owner->connect_opts.custom_headers.strings[i]) {
|
||||
git_str_clear(&buf);
|
||||
git_str_puts(&buf, t->owner->custom_headers.strings[i]);
|
||||
git_str_puts(&buf, t->owner->connect_opts.custom_headers.strings[i]);
|
||||
if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_str_cstr(&buf)) < 0) {
|
||||
git_error_set(GIT_ERROR_OS, "failed to convert custom header to wide characters");
|
||||
goto on_error;
|
||||
@@ -577,14 +577,6 @@ static int winhttp_stream_connect(winhttp_stream *s)
|
||||
}
|
||||
}
|
||||
|
||||
/* If requested, disable certificate validation */
|
||||
if (strcmp(t->server.url.scheme, "https") == 0) {
|
||||
int flags;
|
||||
|
||||
if (t->owner->parent.read_flags(&t->owner->parent, &flags) < 0)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if ((error = apply_credentials(s->request, &t->server.url, WINHTTP_AUTH_TARGET_SERVER, t->server.cred, t->server.auth_mechanisms)) < 0)
|
||||
goto on_error;
|
||||
|
||||
@@ -1197,8 +1189,10 @@ replay:
|
||||
winhttp_stream_close(s);
|
||||
|
||||
if (!git__prefixcmp_icase(location8, prefix_https)) {
|
||||
bool follow = (t->owner->connect_opts.follow_redirects != GIT_REMOTE_REDIRECT_NONE);
|
||||
|
||||
/* Upgrade to secure connection; disconnect and start over */
|
||||
if (git_net_url_apply_redirect(&t->server.url, location8, s->service_url) < 0) {
|
||||
if (git_net_url_apply_redirect(&t->server.url, location8, follow, s->service_url) < 0) {
|
||||
git__free(location8);
|
||||
return -1;
|
||||
}
|
||||
@@ -1218,8 +1212,8 @@ replay:
|
||||
int error = acquire_credentials(s->request,
|
||||
&t->server,
|
||||
t->owner->url,
|
||||
t->owner->cred_acquire_cb,
|
||||
t->owner->cred_acquire_payload);
|
||||
t->owner->connect_opts.callbacks.credentials,
|
||||
t->owner->connect_opts.callbacks.payload);
|
||||
|
||||
if (error < 0) {
|
||||
return error;
|
||||
@@ -1231,9 +1225,9 @@ replay:
|
||||
} else if (status_code == HTTP_STATUS_PROXY_AUTH_REQ) {
|
||||
int error = acquire_credentials(s->request,
|
||||
&t->proxy,
|
||||
t->owner->proxy.url,
|
||||
t->owner->proxy.credentials,
|
||||
t->owner->proxy.payload);
|
||||
t->owner->connect_opts.proxy_opts.url,
|
||||
t->owner->connect_opts.proxy_opts.credentials,
|
||||
t->owner->connect_opts.proxy_opts.payload);
|
||||
|
||||
if (error < 0) {
|
||||
return error;
|
||||
|
||||
@@ -31,7 +31,7 @@ struct git_worktree {
|
||||
/* Path to the parent's working directory */
|
||||
char *parent_path;
|
||||
|
||||
int locked:1;
|
||||
unsigned int locked:1;
|
||||
};
|
||||
|
||||
char *git_worktree__read_link(const char *base, const char *file);
|
||||
|
||||
@@ -148,3 +148,28 @@ void test_config_conditionals__onbranch(void)
|
||||
assert_condition_includes("onbranch", "dir*", false);
|
||||
assert_condition_includes("onbranch", "dir/*", false);
|
||||
}
|
||||
|
||||
void test_config_conditionals__empty(void)
|
||||
{
|
||||
git_buf value = GIT_BUF_INIT;
|
||||
git_str buf = GIT_STR_INIT;
|
||||
git_config *cfg;
|
||||
|
||||
cl_git_pass(git_str_puts(&buf, "[includeIf]\n"));
|
||||
cl_git_pass(git_str_puts(&buf, "path = other\n"));
|
||||
|
||||
cl_git_mkfile("empty_standard_repo/.git/config", buf.ptr);
|
||||
cl_git_mkfile("empty_standard_repo/.git/other", "[foo]\nbar=baz\n");
|
||||
_repo = cl_git_sandbox_reopen();
|
||||
|
||||
git_str_dispose(&buf);
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, _repo));
|
||||
|
||||
cl_git_fail_with(GIT_ENOTFOUND,
|
||||
git_config_get_string_buf(&value, cfg, "foo.bar"));
|
||||
|
||||
git_str_dispose(&buf);
|
||||
git_buf_dispose(&value);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ void test_network_url_redirect__cleanup(void)
|
||||
void test_network_url_redirect__redirect_http(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"http://example.com/foo/bar/baz"));
|
||||
"http://example.com/foo/bar/baz"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"http://example.com/foo/bar/baz", "bar/baz"));
|
||||
"http://example.com/foo/bar/baz", false, "bar/baz"));
|
||||
cl_assert_equal_s(conndata.scheme, "http");
|
||||
cl_assert_equal_s(conndata.host, "example.com");
|
||||
cl_assert_equal_s(conndata.port, "80");
|
||||
@@ -31,9 +31,9 @@ void test_network_url_redirect__redirect_http(void)
|
||||
void test_network_url_redirect__redirect_ssl(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://example.com/foo/bar/baz"));
|
||||
"https://example.com/foo/bar/baz"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"https://example.com/foo/bar/baz", "bar/baz"));
|
||||
"https://example.com/foo/bar/baz", false, "bar/baz"));
|
||||
cl_assert_equal_s(conndata.scheme, "https");
|
||||
cl_assert_equal_s(conndata.host, "example.com");
|
||||
cl_assert_equal_s(conndata.port, "443");
|
||||
@@ -45,9 +45,9 @@ void test_network_url_redirect__redirect_ssl(void)
|
||||
void test_network_url_redirect__redirect_leaves_root_path(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://example.com/foo/bar/baz"));
|
||||
"https://example.com/foo/bar/baz"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"https://example.com/foo/bar/baz", "/foo/bar/baz"));
|
||||
"https://example.com/foo/bar/baz", false, "/foo/bar/baz"));
|
||||
cl_assert_equal_s(conndata.scheme, "https");
|
||||
cl_assert_equal_s(conndata.host, "example.com");
|
||||
cl_assert_equal_s(conndata.port, "443");
|
||||
@@ -59,9 +59,9 @@ void test_network_url_redirect__redirect_leaves_root_path(void)
|
||||
void test_network_url_redirect__redirect_encoded_username_password(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
|
||||
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", "bar/baz"));
|
||||
"https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", false, "bar/baz"));
|
||||
cl_assert_equal_s(conndata.scheme, "https");
|
||||
cl_assert_equal_s(conndata.host, "example.com");
|
||||
cl_assert_equal_s(conndata.port, "443");
|
||||
@@ -70,27 +70,42 @@ void test_network_url_redirect__redirect_encoded_username_password(void)
|
||||
cl_assert_equal_s(conndata.password, "pass@word%zyx%v");
|
||||
}
|
||||
|
||||
void test_network_url_redirect__redirect_cross_host_allowed(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://bar.com/bar/baz"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"https://foo.com/bar/baz", true, NULL));
|
||||
cl_assert_equal_s(conndata.scheme, "https");
|
||||
cl_assert_equal_s(conndata.host, "foo.com");
|
||||
cl_assert_equal_s(conndata.port, "443");
|
||||
cl_assert_equal_s(conndata.path, "/bar/baz");
|
||||
cl_assert_equal_p(conndata.username, NULL);
|
||||
cl_assert_equal_p(conndata.password, NULL);
|
||||
}
|
||||
|
||||
void test_network_url_redirect__redirect_cross_host_denied(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz"));
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://bar.com/bar/baz"));
|
||||
cl_git_fail_with(git_net_url_apply_redirect(&conndata,
|
||||
"https://foo.com/bar/baz", NULL),
|
||||
-1);
|
||||
"https://foo.com/bar/baz", false, NULL), -1);
|
||||
}
|
||||
|
||||
void test_network_url_redirect__redirect_http_downgrade_denied(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz"));
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://foo.com/bar/baz"));
|
||||
cl_git_fail_with(git_net_url_apply_redirect(&conndata,
|
||||
"http://foo.com/bar/baz", NULL),
|
||||
-1);
|
||||
"http://foo.com/bar/baz", true, NULL), -1);
|
||||
}
|
||||
|
||||
void test_network_url_redirect__redirect_relative(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff"));
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"http://foo.com/bar/baz/biff"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"/zap/baz/biff?bam", NULL));
|
||||
"/zap/baz/biff?bam", true, NULL));
|
||||
cl_assert_equal_s(conndata.scheme, "http");
|
||||
cl_assert_equal_s(conndata.host, "foo.com");
|
||||
cl_assert_equal_s(conndata.port, "80");
|
||||
@@ -101,9 +116,10 @@ void test_network_url_redirect__redirect_relative(void)
|
||||
|
||||
void test_network_url_redirect__redirect_relative_ssl(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff"));
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://foo.com/bar/baz/biff"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"/zap/baz/biff?bam", NULL));
|
||||
"/zap/baz/biff?bam", true, NULL));
|
||||
cl_assert_equal_s(conndata.scheme, "https");
|
||||
cl_assert_equal_s(conndata.host, "foo.com");
|
||||
cl_assert_equal_s(conndata.port, "443");
|
||||
@@ -114,16 +130,18 @@ void test_network_url_redirect__redirect_relative_ssl(void)
|
||||
|
||||
void test_network_url_redirect__service_query_no_query_params_in_location(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://foo.com/bar/info/refs?service=git-upload-pack"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"/baz/info/refs", "/info/refs?service=git-upload-pack"));
|
||||
"/baz/info/refs", true, "/info/refs?service=git-upload-pack"));
|
||||
cl_assert_equal_s(conndata.path, "/baz");
|
||||
}
|
||||
|
||||
void test_network_url_redirect__service_query_with_query_params_in_location(void)
|
||||
{
|
||||
cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
|
||||
cl_git_pass(git_net_url_parse(&conndata,
|
||||
"https://foo.com/bar/info/refs?service=git-upload-pack"));
|
||||
cl_git_pass(git_net_url_apply_redirect(&conndata,
|
||||
"/baz/info/refs?service=git-upload-pack", "/info/refs?service=git-upload-pack"));
|
||||
"/baz/info/refs?service=git-upload-pack", true, "/info/refs?service=git-upload-pack"));
|
||||
cl_assert_equal_s(conndata.path, "/baz");
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ static char *_remote_proxy_user = NULL;
|
||||
static char *_remote_proxy_pass = NULL;
|
||||
static char *_remote_proxy_selfsigned = NULL;
|
||||
static char *_remote_expectcontinue = NULL;
|
||||
static char *_remote_redirect_initial = NULL;
|
||||
static char *_remote_redirect_subsequent = NULL;
|
||||
|
||||
static int _orig_proxies_need_reset = 0;
|
||||
static char *_orig_http_proxy = NULL;
|
||||
@@ -78,6 +80,8 @@ void test_online_clone__initialize(void)
|
||||
_remote_proxy_pass = cl_getenv("GITTEST_REMOTE_PROXY_PASS");
|
||||
_remote_proxy_selfsigned = cl_getenv("GITTEST_REMOTE_PROXY_SELFSIGNED");
|
||||
_remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE");
|
||||
_remote_redirect_initial = cl_getenv("GITTEST_REMOTE_REDIRECT_INITIAL");
|
||||
_remote_redirect_subsequent = cl_getenv("GITTEST_REMOTE_REDIRECT_SUBSEQUENT");
|
||||
|
||||
if (_remote_expectcontinue)
|
||||
git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1);
|
||||
@@ -92,6 +96,8 @@ void test_online_clone__cleanup(void)
|
||||
g_repo = NULL;
|
||||
}
|
||||
cl_fixture_cleanup("./foo");
|
||||
cl_fixture_cleanup("./initial");
|
||||
cl_fixture_cleanup("./subsequent");
|
||||
|
||||
git__free(_remote_url);
|
||||
git__free(_remote_user);
|
||||
@@ -107,6 +113,8 @@ void test_online_clone__cleanup(void)
|
||||
git__free(_remote_proxy_pass);
|
||||
git__free(_remote_proxy_selfsigned);
|
||||
git__free(_remote_expectcontinue);
|
||||
git__free(_remote_redirect_initial);
|
||||
git__free(_remote_redirect_subsequent);
|
||||
|
||||
if (_orig_proxies_need_reset) {
|
||||
cl_setenv("HTTP_PROXY", _orig_http_proxy);
|
||||
@@ -938,3 +946,59 @@ void test_online_clone__path_whitespace(void)
|
||||
cl_git_pass(git_clone(&g_repo, "https://libgit2@dev.azure.com/libgit2/test/_git/spaces%20in%20the%20name", "./foo", &g_options));
|
||||
cl_assert(git_fs_path_exists("./foo/master.txt"));
|
||||
}
|
||||
|
||||
void test_online_clone__redirect_default_succeeds_for_initial(void)
|
||||
{
|
||||
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
|
||||
|
||||
if (!_remote_redirect_initial || !_remote_redirect_subsequent)
|
||||
cl_skip();
|
||||
|
||||
cl_git_pass(git_clone(&g_repo, _remote_redirect_initial, "./initial", &options));
|
||||
}
|
||||
|
||||
void test_online_clone__redirect_default_fails_for_subsequent(void)
|
||||
{
|
||||
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
|
||||
|
||||
if (!_remote_redirect_initial || !_remote_redirect_subsequent)
|
||||
cl_skip();
|
||||
|
||||
cl_git_fail(git_clone(&g_repo, _remote_redirect_subsequent, "./fail", &options));
|
||||
}
|
||||
|
||||
void test_online_clone__redirect_none(void)
|
||||
{
|
||||
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
|
||||
|
||||
if (!_remote_redirect_initial)
|
||||
cl_skip();
|
||||
|
||||
options.fetch_opts.follow_redirects = GIT_REMOTE_REDIRECT_NONE;
|
||||
|
||||
cl_git_fail(git_clone(&g_repo, _remote_redirect_initial, "./fail", &options));
|
||||
}
|
||||
|
||||
void test_online_clone__redirect_initial_succeeds_for_initial(void)
|
||||
{
|
||||
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
|
||||
|
||||
if (!_remote_redirect_initial || !_remote_redirect_subsequent)
|
||||
cl_skip();
|
||||
|
||||
options.fetch_opts.follow_redirects = GIT_REMOTE_REDIRECT_INITIAL;
|
||||
|
||||
cl_git_pass(git_clone(&g_repo, _remote_redirect_initial, "./initial", &options));
|
||||
}
|
||||
|
||||
void test_online_clone__redirect_initial_fails_for_subsequent(void)
|
||||
{
|
||||
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
|
||||
|
||||
if (!_remote_redirect_initial || !_remote_redirect_subsequent)
|
||||
cl_skip();
|
||||
|
||||
options.fetch_opts.follow_redirects = GIT_REMOTE_REDIRECT_INITIAL;
|
||||
|
||||
cl_git_fail(git_clone(&g_repo, _remote_redirect_subsequent, "./fail", &options));
|
||||
}
|
||||
|
||||
@@ -7,15 +7,19 @@ static char *_remote_proxy_scheme = NULL;
|
||||
static char *_remote_proxy_host = NULL;
|
||||
static char *_remote_proxy_user = NULL;
|
||||
static char *_remote_proxy_pass = NULL;
|
||||
static char *_remote_redirect_initial = NULL;
|
||||
static char *_remote_redirect_subsequent = NULL;
|
||||
|
||||
void test_online_fetch__initialize(void)
|
||||
{
|
||||
cl_git_pass(git_repository_init(&_repo, "./fetch", 0));
|
||||
|
||||
_remote_proxy_scheme = cl_getenv("GITTEST_REMOTE_PROXY_SCHEME");
|
||||
_remote_proxy_host = cl_getenv("GITTEST_REMOTE_PROXY_HOST");
|
||||
_remote_proxy_user = cl_getenv("GITTEST_REMOTE_PROXY_USER");
|
||||
_remote_proxy_pass = cl_getenv("GITTEST_REMOTE_PROXY_PASS");
|
||||
_remote_proxy_scheme = cl_getenv("GITTEST_REMOTE_PROXY_SCHEME");
|
||||
_remote_proxy_host = cl_getenv("GITTEST_REMOTE_PROXY_HOST");
|
||||
_remote_proxy_user = cl_getenv("GITTEST_REMOTE_PROXY_USER");
|
||||
_remote_proxy_pass = cl_getenv("GITTEST_REMOTE_PROXY_PASS");
|
||||
_remote_redirect_initial = cl_getenv("GITTEST_REMOTE_REDIRECT_INITIAL");
|
||||
_remote_redirect_subsequent = cl_getenv("GITTEST_REMOTE_REDIRECT_SUBSEQUENT");
|
||||
}
|
||||
|
||||
void test_online_fetch__cleanup(void)
|
||||
@@ -24,11 +28,14 @@ void test_online_fetch__cleanup(void)
|
||||
_repo = NULL;
|
||||
|
||||
cl_fixture_cleanup("./fetch");
|
||||
cl_fixture_cleanup("./redirected");
|
||||
|
||||
git__free(_remote_proxy_scheme);
|
||||
git__free(_remote_proxy_host);
|
||||
git__free(_remote_proxy_user);
|
||||
git__free(_remote_proxy_pass);
|
||||
git__free(_remote_proxy_scheme);
|
||||
git__free(_remote_proxy_host);
|
||||
git__free(_remote_proxy_user);
|
||||
git__free(_remote_proxy_pass);
|
||||
git__free(_remote_redirect_initial);
|
||||
git__free(_remote_redirect_subsequent);
|
||||
}
|
||||
|
||||
static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *data)
|
||||
@@ -247,3 +254,44 @@ void test_online_fetch__proxy(void)
|
||||
git_remote_free(remote);
|
||||
git_str_dispose(&url);
|
||||
}
|
||||
|
||||
static int do_redirected_fetch(const char *url, const char *name, const char *config)
|
||||
{
|
||||
git_repository *repo;
|
||||
git_remote *remote;
|
||||
int error;
|
||||
|
||||
cl_git_pass(git_repository_init(&repo, "./redirected", 0));
|
||||
cl_fixture_cleanup(name);
|
||||
|
||||
if (config)
|
||||
cl_repo_set_string(repo, "http.followRedirects", config);
|
||||
|
||||
cl_git_pass(git_remote_create(&remote, repo, name, url));
|
||||
error = git_remote_fetch(remote, NULL, NULL, NULL);
|
||||
|
||||
git_remote_free(remote);
|
||||
git_repository_free(repo);
|
||||
|
||||
cl_fixture_cleanup("./redirected");
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void test_online_fetch__redirect_config(void)
|
||||
{
|
||||
if (!_remote_redirect_initial || !_remote_redirect_subsequent)
|
||||
cl_skip();
|
||||
|
||||
/* config defaults */
|
||||
cl_git_pass(do_redirected_fetch(_remote_redirect_initial, "initial", NULL));
|
||||
cl_git_fail(do_redirected_fetch(_remote_redirect_subsequent, "subsequent", NULL));
|
||||
|
||||
/* redirect=initial */
|
||||
cl_git_pass(do_redirected_fetch(_remote_redirect_initial, "initial", "initial"));
|
||||
cl_git_fail(do_redirected_fetch(_remote_redirect_subsequent, "subsequent", "initial"));
|
||||
|
||||
/* redirect=false */
|
||||
cl_git_fail(do_redirected_fetch(_remote_redirect_initial, "initial", "false"));
|
||||
cl_git_fail(do_redirected_fetch(_remote_redirect_subsequent, "subsequent", "false"));
|
||||
}
|
||||
|
||||
1
tests/resources/renames/.gitted/objects/41/a766bb079e18ff6a24571831bd751168799a02
vendored
Normal file
1
tests/resources/renames/.gitted/objects/41/a766bb079e18ff6a24571831bd751168799a02
vendored
Normal file
@@ -0,0 +1 @@
|
||||
xŽKNÄ0DYű˝GDţŹ#!Ä€C¸ÓÝK‰=ň8pz‚¸‹ZÔ[Ô«Ąí{`g÷4:3`N¨µźŤ?<3F>ĆÎč…E‚Á ”Bp<42>8™Ő=w®ĚLä, š`uŽžbÎśháČâ#ÉVŚSů·Öᣬopí˝}Ăë%č<>ÜsţmďÇ<C48F>űcŞó}űšÖ2nNKŰßŔDoô%xáE'ŐIĎ×<C48E>˙kO]‰J]AĘĆ0 ńĆ<C584> Z…Ęźţ”ęƆ_[
|
||||
BIN
tests/resources/renames/.gitted/objects/ba/8b004914491b129b4feff51b5fd8553b8e8156
vendored
Normal file
BIN
tests/resources/renames/.gitted/objects/ba/8b004914491b129b4feff51b5fd8553b8e8156
vendored
Normal file
Binary file not shown.
BIN
tests/resources/renames/.gitted/objects/e5/6d39ca6d946331aa79c9c443d46c8a6ed4f550
vendored
Normal file
BIN
tests/resources/renames/.gitted/objects/e5/6d39ca6d946331aa79c9c443d46c8a6ed4f550
vendored
Normal file
Binary file not shown.
1
tests/resources/renames/.gitted/refs/heads/case-insensitive-status
vendored
Normal file
1
tests/resources/renames/.gitted/refs/heads/case-insensitive-status
vendored
Normal file
@@ -0,0 +1 @@
|
||||
41a766bb079e18ff6a24571831bd751168799a02
|
||||
@@ -718,3 +718,127 @@ void test_status_renames__precomposed_unicode_toggle_is_rename(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_status_renames__rename_threshold(void)
|
||||
{
|
||||
git_index *index;
|
||||
git_status_list *statuslist;
|
||||
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
||||
|
||||
_rename_helper(g_repo, "ikeepsix.txt", "newname.txt",
|
||||
"Line 1\n" \
|
||||
"Line 2\n" \
|
||||
"Line 3\n" \
|
||||
"Line 4\n" \
|
||||
"Line 5\n" \
|
||||
"Line 6\n" \
|
||||
"Line 7\n" \
|
||||
"Line 8\n" \
|
||||
"Line 9\n"
|
||||
);
|
||||
|
||||
opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR;
|
||||
opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED;
|
||||
|
||||
cl_git_pass(git_repository_index(&index, g_repo));
|
||||
|
||||
/* Default threshold */
|
||||
{
|
||||
struct status_entry expected[] = {
|
||||
{ GIT_STATUS_WT_RENAMED | GIT_STATUS_WT_MODIFIED, "ikeepsix.txt", "newname.txt" },
|
||||
};
|
||||
|
||||
cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts));
|
||||
check_status(statuslist, expected, 1);
|
||||
git_status_list_free(statuslist);
|
||||
}
|
||||
|
||||
/* Threshold set to 90 */
|
||||
{
|
||||
struct status_entry expected[] = {
|
||||
{ GIT_STATUS_WT_DELETED, "ikeepsix.txt", NULL },
|
||||
{ GIT_STATUS_WT_NEW, "newname.txt", NULL }
|
||||
};
|
||||
|
||||
opts.rename_threshold = 90;
|
||||
|
||||
cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts));
|
||||
check_status(statuslist, expected, 2);
|
||||
git_status_list_free(statuslist);
|
||||
}
|
||||
|
||||
/* Threshold set to 25 */
|
||||
{
|
||||
struct status_entry expected[] = {
|
||||
{ GIT_STATUS_WT_RENAMED | GIT_STATUS_WT_MODIFIED, "ikeepsix.txt", "newname.txt" },
|
||||
};
|
||||
|
||||
opts.rename_threshold = 25;
|
||||
|
||||
cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts));
|
||||
check_status(statuslist, expected, 1);
|
||||
git_status_list_free(statuslist);
|
||||
}
|
||||
|
||||
git_index_free(index);
|
||||
}
|
||||
|
||||
void test_status_renames__case_insensitive_h2i_and_i2wc(void)
|
||||
{
|
||||
git_status_list *statuslist;
|
||||
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
||||
git_reference *head, *test_branch;
|
||||
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
git_str path_to_delete = GIT_STR_INIT;
|
||||
git_str path_to_edit = GIT_STR_INIT;
|
||||
git_index *index;
|
||||
git_strarray paths = { NULL, 0 };
|
||||
|
||||
struct status_entry expected[] = {
|
||||
{ GIT_STATUS_INDEX_RENAMED | GIT_STATUS_WT_MODIFIED, "sixserving.txt", "sixserving-renamed.txt" },
|
||||
{ GIT_STATUS_INDEX_DELETED, "Wow.txt", "Wow.txt" }
|
||||
};
|
||||
|
||||
|
||||
/* Checkout the correct branch */
|
||||
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD"));
|
||||
cl_git_pass(git_reference_symbolic_set_target(
|
||||
&test_branch, head, "refs/heads/case-insensitive-status", NULL));
|
||||
cl_git_pass(git_checkout_head(g_repo, &checkout_opts));
|
||||
|
||||
cl_git_pass(git_repository_index(&index, g_repo));
|
||||
|
||||
|
||||
/* Rename sixserving.txt, delete Wow.txt, and stage those changes */
|
||||
rename_file(g_repo, "sixserving.txt", "sixserving-renamed.txt");
|
||||
cl_git_pass(git_str_joinpath(
|
||||
&path_to_delete, git_repository_workdir(g_repo), "Wow.txt"));
|
||||
cl_git_rmfile(path_to_delete.ptr);
|
||||
|
||||
cl_git_pass(git_index_add_all(index, &paths, GIT_INDEX_ADD_FORCE, NULL, NULL));
|
||||
cl_git_pass(git_index_write(index));
|
||||
|
||||
|
||||
/* Change content of sixserving-renamed.txt */
|
||||
cl_git_pass(git_str_joinpath(
|
||||
&path_to_edit, git_repository_workdir(g_repo), "sixserving-renamed.txt"));
|
||||
cl_git_append2file(path_to_edit.ptr, "New content\n");
|
||||
|
||||
/* Run status */
|
||||
opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED;
|
||||
opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR;
|
||||
opts.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX;
|
||||
opts.flags |= GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY;
|
||||
|
||||
cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts));
|
||||
check_status(statuslist, expected, 2);
|
||||
git_status_list_free(statuslist);
|
||||
|
||||
git_index_free(index);
|
||||
|
||||
git_str_dispose(&path_to_delete);
|
||||
git_str_dispose(&path_to_edit);
|
||||
|
||||
git_reference_free(head);
|
||||
git_reference_free(test_branch);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user