1616#include "git2/pack.h"
1717#include "git2/commit.h"
1818#include "git2/revparse.h"
19+ #include "git2/push.h"
1920#include "pack-objects.h"
2021#include "refs.h"
2122#include "posix.h"
2223#include "path.h"
2324#include "buffer.h"
2425#include "repository.h"
2526#include "odb.h"
27+ #include "push.h"
28+ #include "remote.h"
2629
2730typedef struct {
2831 git_transport parent ;
@@ -79,8 +82,10 @@ static int add_ref(transport_local *t, const char *name)
7982
8083 head = NULL ;
8184
82- /* If it's not an annotated tag, just get out */
83- if (git_object_type (obj ) != GIT_OBJ_TAG ) {
85+ /* If it's not an annotated tag, or if we're mocking
86+ * git-receive-pack, just get out */
87+ if (git_object_type (obj ) != GIT_OBJ_TAG ||
88+ t -> direction != GIT_DIRECTION_FETCH ) {
8489 git_object_free (obj );
8590 return 0 ;
8691 }
@@ -125,8 +130,8 @@ static int store_refs(transport_local *t)
125130 /* Sort the references first */
126131 git__tsort ((void * * )ref_names .strings , ref_names .count , & git__strcmp_cb );
127132
128- /* Add HEAD */
129- if (add_ref (t , GIT_HEAD_FILE ) < 0 )
133+ /* Add HEAD iff direction is fetch */
134+ if (t -> direction == GIT_DIRECTION_FETCH && add_ref (t , GIT_HEAD_FILE ) < 0 )
130135 goto on_error ;
131136
132137 for (i = 0 ; i < ref_names .count ; ++ i ) {
@@ -245,6 +250,191 @@ static int local_negotiate_fetch(
245250 return 0 ;
246251}
247252
253+ static int local_push_copy_object (
254+ git_odb * local_odb ,
255+ git_odb * remote_odb ,
256+ git_pobject * obj )
257+ {
258+ int error = 0 ;
259+ git_odb_object * odb_obj = NULL ;
260+ git_odb_stream * odb_stream ;
261+ size_t odb_obj_size ;
262+ git_otype odb_obj_type ;
263+ git_oid remote_odb_obj_oid ;
264+
265+ /* Object already exists in the remote ODB; do nothing and return 0*/
266+ if (git_odb_exists (remote_odb , & obj -> id ))
267+ return 0 ;
268+
269+ if ((error = git_odb_read (& odb_obj , local_odb , & obj -> id )) < 0 )
270+ return error ;
271+
272+ odb_obj_size = git_odb_object_size (odb_obj );
273+ odb_obj_type = git_odb_object_type (odb_obj );
274+
275+ if ((error = git_odb_open_wstream (& odb_stream , remote_odb ,
276+ odb_obj_size , odb_obj_type )) < 0 )
277+ goto on_error ;
278+
279+ if (odb_stream -> write (odb_stream , (char * )git_odb_object_data (odb_obj ),
280+ odb_obj_size ) < 0 ||
281+ odb_stream -> finalize_write (& remote_odb_obj_oid , odb_stream ) < 0 ) {
282+ error = -1 ;
283+ } else if (git_oid_cmp (& obj -> id , & remote_odb_obj_oid ) != 0 ) {
284+ giterr_set (GITERR_ODB , "Error when writing object to remote odb "
285+ "during local push operation. Remote odb object oid does not "
286+ "match local oid." );
287+ error = -1 ;
288+ }
289+
290+ odb_stream -> free (odb_stream );
291+
292+ on_error :
293+ git_odb_object_free (odb_obj );
294+ return error ;
295+ }
296+
297+ static int local_push_update_remote_ref (
298+ git_repository * remote_repo ,
299+ const char * lref ,
300+ const char * rref ,
301+ git_oid * loid ,
302+ git_oid * roid )
303+ {
304+ int error ;
305+ git_reference * remote_ref = NULL ;
306+
307+ /* rref will be NULL if it is implicit in the pushspec (e.g. 'b1:') */
308+ rref = rref ? rref : lref ;
309+
310+ if (lref ) {
311+ /* Create or update a ref */
312+ if ((error = git_reference_create (NULL , remote_repo , rref , loid ,
313+ !git_oid_iszero (roid ))) < 0 )
314+ return error ;
315+ } else {
316+ /* Delete a ref */
317+ if ((error = git_reference_lookup (& remote_ref , remote_repo , rref )) < 0 ) {
318+ if (error == GIT_ENOTFOUND )
319+ error = 0 ;
320+ return error ;
321+ }
322+
323+ if ((error = git_reference_delete (remote_ref )) < 0 )
324+ return error ;
325+
326+ git_reference_free (remote_ref );
327+ }
328+
329+ return 0 ;
330+ }
331+
332+ static int local_push (
333+ git_transport * transport ,
334+ git_push * push )
335+ {
336+ transport_local * t = (transport_local * )transport ;
337+ git_odb * remote_odb = NULL ;
338+ git_odb * local_odb = NULL ;
339+ git_repository * remote_repo = NULL ;
340+ push_spec * spec ;
341+ char * url = NULL ;
342+ int error ;
343+ unsigned int i ;
344+ size_t j ;
345+
346+ if ((error = git_repository_open (& remote_repo , push -> remote -> url )) < 0 )
347+ return error ;
348+
349+ /* We don't currently support pushing locally to non-bare repos. Proper
350+ non-bare repo push support would require checking configs to see if
351+ we should override the default 'don't let this happen' behavior */
352+ if (!remote_repo -> is_bare ) {
353+ error = -1 ;
354+ goto on_error ;
355+ }
356+
357+ if ((error = git_repository_odb__weakptr (& remote_odb , remote_repo )) < 0 ||
358+ (error = git_repository_odb__weakptr (& local_odb , push -> repo )) < 0 )
359+ goto on_error ;
360+
361+ for (i = 0 ; i < push -> pb -> nr_objects ; i ++ ) {
362+ if ((error = local_push_copy_object (local_odb , remote_odb ,
363+ & push -> pb -> object_list [i ])) < 0 )
364+ goto on_error ;
365+ }
366+
367+ push -> unpack_ok = 1 ;
368+
369+ git_vector_foreach (& push -> specs , j , spec ) {
370+ push_status * status ;
371+ const git_error * last ;
372+ char * ref = spec -> rref ? spec -> rref : spec -> lref ;
373+
374+ status = git__calloc (sizeof (push_status ), 1 );
375+ if (!status )
376+ goto on_error ;
377+
378+ status -> ref = git__strdup (ref );
379+ if (!status -> ref ) {
380+ git_push_status_free (status );
381+ goto on_error ;
382+ }
383+
384+ error = local_push_update_remote_ref (remote_repo , spec -> lref , spec -> rref ,
385+ & spec -> loid , & spec -> roid );
386+
387+ switch (error ) {
388+ case GIT_OK :
389+ break ;
390+ case GIT_EINVALIDSPEC :
391+ status -> msg = git__strdup ("funny refname" );
392+ break ;
393+ case GIT_ENOTFOUND :
394+ status -> msg = git__strdup ("Remote branch not found to delete" );
395+ break ;
396+ default :
397+ last = giterr_last ();
398+
399+ if (last && last -> message )
400+ status -> msg = git__strdup (last -> message );
401+ else
402+ status -> msg = git__strdup ("Unspecified error encountered" );
403+ break ;
404+ }
405+
406+ /* failed to allocate memory for a status message */
407+ if (error < 0 && !status -> msg ) {
408+ git_push_status_free (status );
409+ goto on_error ;
410+ }
411+
412+ /* failed to insert the ref update status */
413+ if ((error = git_vector_insert (& push -> status , status )) < 0 ) {
414+ git_push_status_free (status );
415+ goto on_error ;
416+ }
417+ }
418+
419+ if (push -> specs .length ) {
420+ int flags = t -> flags ;
421+ url = git__strdup (t -> url );
422+
423+ if (!url || t -> parent .close (& t -> parent ) < 0 ||
424+ t -> parent .connect (& t -> parent , url ,
425+ push -> remote -> cred_acquire_cb , NULL , GIT_DIRECTION_PUSH , flags ))
426+ goto on_error ;
427+ }
428+
429+ error = 0 ;
430+
431+ on_error :
432+ git_repository_free (remote_repo );
433+ git__free (url );
434+
435+ return error ;
436+ }
437+
248438typedef struct foreach_data {
249439 git_transfer_progress * stats ;
250440 git_transfer_progress_callback progress_cb ;
@@ -379,30 +569,39 @@ static void local_cancel(git_transport *transport)
379569static int local_close (git_transport * transport )
380570{
381571 transport_local * t = (transport_local * )transport ;
572+ size_t i ;
573+ git_remote_head * head ;
382574
383575 t -> connected = 0 ;
384- git_repository_free (t -> repo );
385- t -> repo = NULL ;
576+
577+ if (t -> repo ) {
578+ git_repository_free (t -> repo );
579+ t -> repo = NULL ;
580+ }
581+
582+ git_vector_foreach (& t -> refs , i , head ) {
583+ git__free (head -> name );
584+ git__free (head );
585+ }
586+
587+ git_vector_free (& t -> refs );
588+
589+ if (t -> url ) {
590+ git__free (t -> url );
591+ t -> url = NULL ;
592+ }
386593
387594 return 0 ;
388595}
389596
390597static void local_free (git_transport * transport )
391598{
392- unsigned int i ;
393- transport_local * t = (transport_local * ) transport ;
394- git_vector * vec = & t -> refs ;
395- git_remote_head * head ;
396-
397- assert (transport );
599+ transport_local * t = (transport_local * )transport ;
398600
399- git_vector_foreach (vec , i , head ) {
400- git__free (head -> name );
401- git__free (head );
402- }
403- git_vector_free (vec );
601+ /* Close the transport, if it's still open. */
602+ local_close (transport );
404603
405- git__free ( t -> url );
604+ /* Free the transport */
406605 git__free (t );
407606}
408607
@@ -423,6 +622,7 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param)
423622 t -> parent .connect = local_connect ;
424623 t -> parent .negotiate_fetch = local_negotiate_fetch ;
425624 t -> parent .download_pack = local_download_pack ;
625+ t -> parent .push = local_push ;
426626 t -> parent .close = local_close ;
427627 t -> parent .free = local_free ;
428628 t -> parent .ls = local_ls ;
0 commit comments