28#include <wx/filename.h>
30#include <wx/textfile.h>
36 m_repo( aRepo ), m_connType(
GIT_CONN_TYPE::GIT_CONN_LOCAL ), m_testedTypes( 0 )
51 wxCHECK(
m_repo, wxEmptyString );
52 git_reference* head =
nullptr;
54 int retval = git_repository_head( &head,
m_repo );
56 if( retval && retval != GIT_EUNBORNBRANCH && retval != GIT_ENOTFOUND )
59 git_reference *branch;
61 if( git_reference_resolve( &branch, head ) )
63 git_reference_free( head );
67 git_reference_free( head );
68 const char* branchName =
"";
70 if( git_branch_name( &branchName, branch ) )
72 git_reference_free( branch );
76 git_reference_free( branch );
78 return wxString( branchName );
87 std::vector<wxString> branchNames;
88 std::map<git_time_t, wxString> branchNamesMap;
91 git_branch_iterator* branchIterator =
nullptr;
93 if( git_branch_iterator_new( &branchIterator,
m_repo, GIT_BRANCH_LOCAL ) )
96 git_reference* branchReference =
nullptr;
97 git_branch_t branchType;
99 while( git_branch_next( &branchReference, &branchType, branchIterator ) != GIT_ITEROVER )
101 const char* branchName =
"";
103 if( git_branch_name( &branchName, branchReference ) )
106 const git_oid* commitId = git_reference_target( branchReference );
108 git_commit* commit =
nullptr;
110 if( git_commit_lookup( &commit,
m_repo, commitId ) )
113 git_time_t commitTime = git_commit_time( commit );
115 if( git_branch_is_head( branchReference ) )
116 firstName = branchName;
118 branchNamesMap.emplace( commitTime, branchName );
120 git_commit_free( commit );
121 git_reference_free( branchReference );
124 git_branch_iterator_free( branchIterator );
127 if( !firstName.IsEmpty() )
128 branchNames.push_back( firstName );
131 for(
auto rit = branchNamesMap.rbegin(); rit != branchNamesMap.rend(); ++rit )
132 branchNames.push_back( rit->second );
141 std::vector<wxString> projDirs;
147 if( git_reference_name_to_id( &oid,
m_repo,
"HEAD" ) != GIT_OK )
149 wxLogError(
"An error occurred: %s", git_error_last()->message );
153 if( git_commit_lookup( &commit,
m_repo, &oid ) != GIT_OK )
155 wxLogError(
"An error occurred: %s", git_error_last()->message );
159 if( git_commit_tree( &tree, commit ) != GIT_OK )
161 wxLogError(
"An error occurred: %s", git_error_last()->message );
167 tree, GIT_TREEWALK_PRE,
168 [](
const char* root,
const git_tree_entry* entry,
void* payload )
170 std::vector<wxString>* prjs =
static_cast<std::vector<wxString>*
>( payload );
171 wxFileName root_fn( git_tree_entry_name( entry ) );
173 root_fn.SetPath( root );
175 if( git_tree_entry_type( entry ) == GIT_OBJECT_BLOB
176 && ( ( root_fn.GetExt() ==
"kicad_pro" ) || ( root_fn.GetExt() ==
"pro" ) ) )
178 prjs->push_back( root_fn.GetFullPath() );
185 git_tree_free( tree );
186 git_commit_free( commit );
188 std::sort( projDirs.begin(), projDirs.end(),
189 [](
const wxString& a,
const wxString& b )
191 int a_freq = a.Freq( wxFileName::GetPathSeparator() );
192 int b_freq = b.Freq( wxFileName::GetPathSeparator() );
194 if( a_freq == b_freq )
197 return a_freq < b_freq;
207 auto get_modified_files = [&]( git_oid* from_oid, git_oid* to_oid ) -> std::set<wxString>
209 std::set<wxString> modified_set;
210 git_revwalk* walker =
nullptr;
212 if( git_revwalk_new( &walker,
m_repo ) != GIT_OK )
215 if( ( git_revwalk_push( walker, from_oid ) != GIT_OK )
216 || ( git_revwalk_hide( walker, to_oid ) != GIT_OK ) )
218 git_revwalk_free( walker );
226 while( git_revwalk_next( &oid, walker ) == GIT_OK )
228 if( git_commit_lookup( &commit,
m_repo, &oid ) != GIT_OK )
231 git_tree *tree, *parent_tree =
nullptr;
232 if( git_commit_tree( &tree, commit ) != GIT_OK )
234 git_commit_free( commit );
239 if( !git_commit_parentcount( commit ) )
241 git_tree_free( tree );
242 git_commit_free( commit );
248 if( git_commit_parent( &parent, commit, 0 ) != GIT_OK )
250 git_tree_free( tree );
251 git_commit_free( commit );
256 if( git_commit_tree( &parent_tree, parent ) != GIT_OK )
258 git_tree_free( tree );
259 git_commit_free( commit );
260 git_commit_free( parent );
266 git_diff_options diff_opts;
267 git_diff_init_options( &diff_opts, GIT_DIFF_OPTIONS_VERSION );
269 if( git_diff_tree_to_tree( &diff,
m_repo, parent_tree, tree, &diff_opts ) == GIT_OK )
271 size_t num_deltas = git_diff_num_deltas( diff );
273 for(
size_t i = 0; i < num_deltas; ++i )
275 const git_diff_delta*
delta = git_diff_get_delta( diff, i );
276 modified_set.insert(
delta->new_file.path );
279 git_diff_free( diff );
282 git_tree_free( parent_tree );
283 git_commit_free( parent );
284 git_tree_free( tree );
285 git_commit_free( commit );
288 git_revwalk_free( walker );
293 std::pair<std::set<wxString>,std::set<wxString>> modified_files;
296 return modified_files;
298 git_reference* head =
nullptr;
299 git_reference* remote_head =
nullptr;
301 if( git_repository_head( &head,
m_repo ) != GIT_OK )
302 return modified_files;
304 if( git_branch_upstream( &remote_head, head ) != GIT_OK )
306 git_reference_free( head );
307 return modified_files;
310 git_oid head_oid = *git_reference_target( head );
311 git_oid remote_oid = *git_reference_target( remote_head );
313 git_reference_free( head );
314 git_reference_free( remote_head );
316 modified_files.first = get_modified_files( &head_oid, &remote_oid );
317 modified_files.second = get_modified_files( &remote_oid, &head_oid );
319 return modified_files;
328 git_reference* head =
nullptr;
329 git_reference* remote_head =
nullptr;
331 if( git_repository_head( &head,
m_repo ) != GIT_OK )
334 if( git_branch_upstream( &remote_head, head ) != GIT_OK )
336 git_reference_free( head );
340 git_oid head_oid = *git_reference_target( head );
341 git_oid remote_oid = *git_reference_target( remote_head );
343 git_reference_free( head );
344 git_reference_free( remote_head );
346 git_revwalk* walker =
nullptr;
348 if( git_revwalk_new( &walker,
m_repo ) != GIT_OK )
351 if( ( git_revwalk_push( walker, &head_oid ) != GIT_OK )
352 || ( git_revwalk_hide( walker, &remote_oid ) != GIT_OK ) )
354 git_revwalk_free( walker );
361 if( git_revwalk_next( &oid, walker ) != GIT_OK )
363 git_revwalk_free( walker );
367 git_revwalk_free( walker );
375 git_remote* remote =
nullptr;
377 if( git_remote_lookup( &remote,
m_repo,
"origin" ) != GIT_OK )
383 const char* fetch_url = git_remote_url( remote );
384 const char* push_url = git_remote_pushurl( remote );
389 push_url = fetch_url;
393 git_remote_free( remote );
396 return fetch_url && push_url;
402 wxCHECK(
m_repo, wxEmptyString );
405 git_reference* head =
nullptr;
406 git_reference* upstream =
nullptr;
408 if( git_repository_head( &head,
m_repo ) != GIT_OK )
411 if( git_branch_upstream( &upstream, head ) == GIT_OK )
413 git_buf remote_name = GIT_BUF_INIT_CONST(
nullptr, 0 );
415 if( git_branch_remote_name( &remote_name,
m_repo, git_reference_name( upstream ) ) == GIT_OK )
417 retval = remote_name.ptr;
418 git_buf_dispose( &remote_name );
421 git_reference_free( upstream );
424 git_reference_free( head );
443 return wxEmptyString;
445 const char *
path = git_repository_path(
m_repo );
446 wxString retval =
path;
455 wxFileName keyFile( wxGetHomeDir(), wxEmptyString );
456 keyFile.AppendDir(
".ssh" );
457 keyFile.SetFullName(
"id_rsa" );
459 if( keyFile.FileExists() )
462 keyFile.SetFullName(
"id_dsa" );
464 if( keyFile.FileExists() )
467 keyFile.SetFullName(
"id_ecdsa" );
469 if( keyFile.FileExists() )
472 keyFile.SetFullName(
"id_ed25519" );
474 if( keyFile.FileExists() )
478 wxFileName sshConfig( wxGetHomeDir(), wxEmptyString );
479 sshConfig.AppendDir(
".ssh" );
480 sshConfig.SetFullName(
"config" );
482 if( sshConfig.FileExists() )
484 wxTextFile configFile( sshConfig.GetFullPath() );
489 for( wxString line = configFile.GetFirstLine(); !configFile.Eof(); line = configFile.GetNextLine() )
491 line.Trim(
false ).Trim(
true );
493 if( line.StartsWith(
"Host " ) )
498 if( line.StartsWith(
"Host" ) && line.Contains(
m_hostname ) )
501 if( match && line.StartsWith(
"IdentityFile" ) )
503 wxString keyPath = line.AfterFirst(
' ' ).Trim(
false ).Trim(
true );
506 if( keyPath.StartsWith(
"~" ) )
507 keyPath.Replace(
"~", wxGetHomeDir(),
false );
510 if( wxFileName::FileExists( keyPath ) )
528 git_remote* remote =
nullptr;
530 if( git_remote_lookup( &remote,
m_repo, remote_name.ToStdString().c_str() ) == GIT_OK )
532 const char* url = git_remote_url( remote );
537 git_remote_free( remote );
559 size_t atPos = uri.find(
'@' );
561 if( atPos != wxString::npos )
563 size_t protoEnd = uri.find(
"//" );
565 if( protoEnd != wxString::npos )
567 wxString credentials = uri.Mid( protoEnd + 2, atPos - protoEnd - 2 );
568 size_t colonPos = credentials.find(
':' );
570 if( colonPos != wxString::npos )
573 m_password = credentials.Mid( colonPos + 1, credentials.Length() - colonPos - 1 );
589 size_t colonPos =
m_remote.find(
':' );
590 if( colonPos != wxString::npos )
596 size_t hostStart =
m_remote.find(
"://" ) + 2;
597 size_t hostEnd =
m_remote.find(
'/', hostStart );
600 if( hostEnd != wxString::npos )
601 host =
m_remote.Mid( hostStart, hostEnd - hostStart );
605 atPos = host.find(
'@' );
607 if( atPos != wxString::npos )
617 const git_oid* aOID,
unsigned int aIsMerge,
void* aPayload )
620 git_oid_cpy( (git_oid*) aPayload, aOID );
630 wxString progressMessage( aStr );
639 wxString progressMessage( str, len );
649 wxString progressMessage = wxString::Format(
_(
"Received %u of %u objects" ),
650 aStats->received_objects,
651 aStats->total_objects );
653 parent->
UpdateProgress( aStats->received_objects, aStats->total_objects, progressMessage );
659extern "C" int update_cb(
const char* aRefname,
const git_oid* aFirst,
const git_oid* aSecond,
662 constexpr int cstring_len = 8;
663 char a_str[cstring_len + 1];
664 char b_str[cstring_len + 1];
669 git_oid_tostr( b_str, cstring_len, aSecond );
671#if ( LIBGIT2_VER_MAJOR >= 1 ) || ( LIBGIT2_VER_MINOR >= 99 )
672 if( !git_oid_is_zero( aFirst ) )
674 if( !git_oid_iszero( aFirst ) )
677 git_oid_tostr( a_str, cstring_len, aFirst );
678 status = wxString::Format(
_(
"* [updated] %s..%s %s" ), a_str, b_str, aRefname );
682 status = wxString::Format(
_(
"* [new] %s %s" ), b_str, aRefname );
694 long long progress = 100;
699 progress = ( aCurrent * 100ll ) / aTotal;
702 wxString progressMessage = wxString::Format(
_(
"Writing objects: %lld%% (%u/%u), %zu bytes" ),
703 progress, aCurrent, aTotal, aBytes );
713 wxString status( aStatus );
715 if( !status.IsEmpty() )
717 wxString statusMessage = wxString::Format(
_(
"* [rejected] %s (%s)" ), aRefname, aStatus );
722 wxString statusMessage = wxString::Format(
_(
"[updated] %s" ), aRefname );
730extern "C" int credentials_cb( git_cred** aOut,
const char* aUrl,
const char* aUsername,
731 unsigned int aAllowedTypes,
void* aPayload )
736 return GIT_PASSTHROUGH;
738 if( aAllowedTypes & GIT_CREDTYPE_USERNAME
739 && !( parent->
TestedTypes() & GIT_CREDTYPE_USERNAME ) )
741 wxString username = parent->
GetUsername().Trim().Trim(
false );
742 git_cred_username_new( aOut, username.ToStdString().c_str() );
746 && ( aAllowedTypes & GIT_CREDTYPE_USERPASS_PLAINTEXT )
747 && !( parent->
TestedTypes() & GIT_CREDTYPE_USERPASS_PLAINTEXT ) )
749 wxString username = parent->
GetUsername().Trim().Trim(
false );
750 wxString password = parent->
GetPassword().Trim().Trim(
false );
752 git_cred_userpass_plaintext_new( aOut, username.ToStdString().c_str(),
753 password.ToStdString().c_str() );
754 parent->
TestedTypes() |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
757 && ( aAllowedTypes & GIT_CREDTYPE_SSH_KEY )
758 && !( parent->
TestedTypes() & GIT_CREDTYPE_SSH_KEY ) )
763 if( sshKey.IsEmpty() )
766 return GIT_PASSTHROUGH;
769 wxString sshPubKey = sshKey +
".pub";
770 wxString username = parent->
GetUsername().Trim().Trim(
false );
771 wxString password = parent->
GetPassword().Trim().Trim(
false );
773 git_cred_ssh_key_new( aOut, username.ToStdString().c_str(),
774 sshPubKey.ToStdString().c_str(),
775 sshKey.ToStdString().c_str(),
776 password.ToStdString().c_str() );
780 return GIT_PASSTHROUGH;
std::vector< wxString > GetBranchNames() const
void updateConnectionType()
wxString GetCurrentBranchName() const
wxString GetGitRootDirectory() const
void SetSSHKey(const wxString &aSSHKey)
std::vector< wxString > GetProjectDirs()
Return a vector of project files in the repository.
GIT_CONN_TYPE GetConnType() const
wxString GetPassword() const
git_repository * GetRepo() const
wxString GetNextPublicKey()
KIGIT_COMMON(git_repository *aRepo)
std::pair< std::set< wxString >, std::set< wxString > > GetDifferentFiles() const
Return a pair of sets of files that differ locally from the remote repository The first set is files ...
std::vector< wxString > m_publicKeys
bool HasPushAndPullRemote() const
wxString GetUsername() const
void UpdateCurrentBranchInfo()
bool HasLocalCommits() const
virtual void UpdateProgress(int aCurrent, int aTotal, const wxString &aMessage)
wxString GetRemotename() const
void clone_progress_cb(const char *aStr, size_t aLen, size_t aTotal, void *data)
int fetchhead_foreach_cb(const char *, const char *, const git_oid *aOID, unsigned int aIsMerge, void *aPayload)
int push_update_reference_cb(const char *aRefname, const char *aStatus, void *aPayload)
int update_cb(const char *aRefname, const git_oid *aFirst, const git_oid *aSecond, void *aPayload)
int transfer_progress_cb(const git_transfer_progress *aStats, void *aPayload)
int credentials_cb(git_cred **aOut, const char *aUrl, const char *aUsername, unsigned int aAllowedTypes, void *aPayload)
int push_transfer_progress_cb(unsigned int aCurrent, unsigned int aTotal, size_t aBytes, void *aPayload)
int progress_cb(const char *str, int len, void *data)