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 git_reference* head =
nullptr;
53 int retval = git_repository_head( &head,
m_repo );
55 if( retval && retval != GIT_EUNBORNBRANCH && retval != GIT_ENOTFOUND )
58 git_reference *branch;
60 if( git_reference_resolve( &branch, head ) )
62 git_reference_free( head );
66 git_reference_free( head );
67 const char* branchName =
"";
69 if( git_branch_name( &branchName, branch ) )
71 git_reference_free( branch );
75 git_reference_free( branch );
77 return wxString( branchName );
83 std::vector<wxString> branchNames;
84 std::map<git_time_t, wxString> branchNamesMap;
87 git_branch_iterator* branchIterator =
nullptr;
89 if( git_branch_iterator_new( &branchIterator,
m_repo, GIT_BRANCH_LOCAL ) )
92 git_reference* branchReference =
nullptr;
93 git_branch_t branchType;
95 while( git_branch_next( &branchReference, &branchType, branchIterator ) != GIT_ITEROVER )
97 const char* branchName =
"";
99 if( git_branch_name( &branchName, branchReference ) )
102 const git_oid* commitId = git_reference_target( branchReference );
104 git_commit* commit =
nullptr;
106 if( git_commit_lookup( &commit,
m_repo, commitId ) )
109 git_time_t commitTime = git_commit_time( commit );
111 if( git_branch_is_head( branchReference ) )
112 firstName = branchName;
114 branchNamesMap.emplace( commitTime, branchName );
116 git_commit_free( commit );
117 git_reference_free( branchReference );
120 git_branch_iterator_free( branchIterator );
123 if( !firstName.IsEmpty() )
124 branchNames.push_back( firstName );
127 for(
auto rit = branchNamesMap.rbegin(); rit != branchNamesMap.rend(); ++rit )
128 branchNames.push_back( rit->second );
136 std::vector<wxString> projDirs;
142 if( git_reference_name_to_id( &oid,
m_repo,
"HEAD" ) != GIT_OK )
144 wxLogError(
"An error occurred: %s", git_error_last()->message );
148 if( git_commit_lookup( &commit,
m_repo, &oid ) != GIT_OK )
150 wxLogError(
"An error occurred: %s", git_error_last()->message );
154 if( git_commit_tree( &tree, commit ) != GIT_OK )
156 wxLogError(
"An error occurred: %s", git_error_last()->message );
162 tree, GIT_TREEWALK_PRE,
163 [](
const char* root,
const git_tree_entry* entry,
void* payload )
165 std::vector<wxString>* prjs =
static_cast<std::vector<wxString>*
>( payload );
166 wxFileName root_fn( git_tree_entry_name( entry ) );
168 root_fn.SetPath( root );
170 if( git_tree_entry_type( entry ) == GIT_OBJECT_BLOB
171 && ( ( root_fn.GetExt() ==
"kicad_pro" ) || ( root_fn.GetExt() ==
"pro" ) ) )
173 prjs->push_back( root_fn.GetFullPath() );
180 git_tree_free( tree );
181 git_commit_free( commit );
183 std::sort( projDirs.begin(), projDirs.end(),
184 [](
const wxString& a,
const wxString& b )
186 int a_freq = a.Freq( wxFileName::GetPathSeparator() );
187 int b_freq = b.Freq( wxFileName::GetPathSeparator() );
189 if( a_freq == b_freq )
192 return a_freq < b_freq;
202 auto get_modified_files = [&]( git_oid* from_oid, git_oid* to_oid ) -> std::set<wxString>
204 std::set<wxString> modified_set;
205 git_revwalk* walker =
nullptr;
207 if( git_revwalk_new( &walker,
m_repo ) != GIT_OK )
210 if( ( git_revwalk_push( walker, from_oid ) != GIT_OK )
211 || ( git_revwalk_hide( walker, to_oid ) != GIT_OK ) )
213 git_revwalk_free( walker );
221 while( git_revwalk_next( &oid, walker ) == GIT_OK )
223 if( git_commit_lookup( &commit,
m_repo, &oid ) != GIT_OK )
226 git_tree *tree, *parent_tree =
nullptr;
227 if( git_commit_tree( &tree, commit ) != GIT_OK )
229 git_commit_free( commit );
234 if( !git_commit_parentcount( commit ) )
236 git_tree_free( tree );
237 git_commit_free( commit );
243 if( git_commit_parent( &parent, commit, 0 ) != GIT_OK )
245 git_tree_free( tree );
246 git_commit_free( commit );
251 if( git_commit_tree( &parent_tree, parent ) != GIT_OK )
253 git_tree_free( tree );
254 git_commit_free( commit );
255 git_commit_free( parent );
261 git_diff_options diff_opts;
262 git_diff_init_options( &diff_opts, GIT_DIFF_OPTIONS_VERSION );
264 if( git_diff_tree_to_tree( &diff,
m_repo, parent_tree, tree, &diff_opts ) == GIT_OK )
266 size_t num_deltas = git_diff_num_deltas( diff );
268 for(
size_t i = 0; i < num_deltas; ++i )
270 const git_diff_delta*
delta = git_diff_get_delta( diff, i );
271 modified_set.insert(
delta->new_file.path );
274 git_diff_free( diff );
277 git_tree_free( parent_tree );
278 git_commit_free( parent );
279 git_tree_free( tree );
280 git_commit_free( commit );
283 git_revwalk_free( walker );
288 std::pair<std::set<wxString>,std::set<wxString>> modified_files;
291 return modified_files;
293 git_reference* head =
nullptr;
294 git_reference* remote_head =
nullptr;
296 if( git_repository_head( &head,
m_repo ) != GIT_OK )
297 return modified_files;
299 if( git_branch_upstream( &remote_head, head ) != GIT_OK )
301 git_reference_free( head );
302 return modified_files;
305 git_oid head_oid = *git_reference_target( head );
306 git_oid remote_oid = *git_reference_target( remote_head );
308 git_reference_free( head );
309 git_reference_free( remote_head );
311 modified_files.first = get_modified_files( &head_oid, &remote_oid );
312 modified_files.second = get_modified_files( &remote_oid, &head_oid );
314 return modified_files;
323 git_reference* head =
nullptr;
324 git_reference* remote_head =
nullptr;
326 if( git_repository_head( &head,
m_repo ) != GIT_OK )
329 if( git_branch_upstream( &remote_head, head ) != GIT_OK )
331 git_reference_free( head );
335 git_oid head_oid = *git_reference_target( head );
336 git_oid remote_oid = *git_reference_target( remote_head );
338 git_reference_free( head );
339 git_reference_free( remote_head );
341 git_revwalk* walker =
nullptr;
343 if( git_revwalk_new( &walker,
m_repo ) != GIT_OK )
346 if( ( git_revwalk_push( walker, &head_oid ) != GIT_OK )
347 || ( git_revwalk_hide( walker, &remote_oid ) != GIT_OK ) )
349 git_revwalk_free( walker );
356 if( git_revwalk_next( &oid, walker ) != GIT_OK )
358 git_revwalk_free( walker );
362 git_revwalk_free( walker );
369 git_remote* remote =
nullptr;
371 if( git_remote_lookup( &remote,
m_repo,
"origin" ) != GIT_OK )
377 const char* fetch_url = git_remote_url( remote );
378 const char* push_url = git_remote_pushurl( remote );
383 push_url = fetch_url;
387 git_remote_free( remote );
390 return fetch_url && push_url;
397 git_reference* head =
nullptr;
398 git_reference* upstream =
nullptr;
400 if( git_repository_head( &head,
m_repo ) != GIT_OK )
403 if( git_branch_upstream( &upstream, head ) == GIT_OK )
405 git_buf remote_name = GIT_BUF_INIT_CONST(
nullptr, 0 );
407 if( git_branch_remote_name( &remote_name,
m_repo, git_reference_name( upstream ) ) == GIT_OK )
409 retval = remote_name.ptr;
410 git_buf_dispose( &remote_name );
413 git_reference_free( upstream );
416 git_reference_free( head );
436 wxFileName keyFile( wxGetHomeDir(), wxEmptyString );
437 keyFile.AppendDir(
".ssh" );
438 keyFile.SetFullName(
"id_rsa" );
440 if( keyFile.FileExists() )
443 keyFile.SetFullName(
"id_dsa" );
445 if( keyFile.FileExists() )
448 keyFile.SetFullName(
"id_ecdsa" );
450 if( keyFile.FileExists() )
453 keyFile.SetFullName(
"id_ed25519" );
455 if( keyFile.FileExists() )
459 wxFileName sshConfig( wxGetHomeDir(), wxEmptyString );
460 sshConfig.AppendDir(
".ssh" );
461 sshConfig.SetFullName(
"config" );
463 if( sshConfig.FileExists() )
465 wxTextFile configFile( sshConfig.GetFullPath() );
470 for( wxString line = configFile.GetFirstLine(); !configFile.Eof(); line = configFile.GetNextLine() )
472 line.Trim(
false ).Trim(
true );
474 if( line.StartsWith(
"Host " ) )
479 if( line.StartsWith(
"Host" ) && line.Contains(
m_hostname ) )
482 if( match && line.StartsWith(
"IdentityFile" ) )
484 wxString keyPath = line.AfterFirst(
' ' ).Trim(
false ).Trim(
true );
487 if( keyPath.StartsWith(
"~" ) )
488 keyPath.Replace(
"~", wxGetHomeDir(),
false );
491 if( wxFileName::FileExists( keyPath ) )
507 git_remote* remote =
nullptr;
509 if( git_remote_lookup( &remote,
m_repo, remote_name.ToStdString().c_str() ) == GIT_OK )
511 const char* url = git_remote_url( remote );
516 git_remote_free( remote );
538 size_t atPos = uri.find(
'@' );
540 if( atPos != wxString::npos )
542 size_t protoEnd = uri.find(
"//" );
544 if( protoEnd != wxString::npos )
546 wxString credentials = uri.Mid( protoEnd + 2, atPos - protoEnd - 2 );
547 size_t colonPos = credentials.find(
':' );
549 if( colonPos != wxString::npos )
552 m_password = credentials.Mid( colonPos + 1, credentials.Length() - colonPos - 1 );
568 size_t colonPos =
m_remote.find(
':' );
569 if( colonPos != wxString::npos )
575 size_t hostStart =
m_remote.find(
"://" ) + 2;
576 size_t hostEnd =
m_remote.find(
'/', hostStart );
579 if( hostEnd != wxString::npos )
580 host =
m_remote.Mid( hostStart, hostEnd - hostStart );
584 atPos = host.find(
'@' );
586 if( atPos != wxString::npos )
596 const git_oid* aOID,
unsigned int aIsMerge,
void* aPayload )
599 git_oid_cpy( (git_oid*) aPayload, aOID );
609 wxString progressMessage( aStr );
618 wxString progressMessage( str, len );
628 wxString progressMessage = wxString::Format(
_(
"Received %u of %u objects" ),
629 aStats->received_objects,
630 aStats->total_objects );
632 parent->
UpdateProgress( aStats->received_objects, aStats->total_objects, progressMessage );
638extern "C" int update_cb(
const char* aRefname,
const git_oid* aFirst,
const git_oid* aSecond,
641 constexpr int cstring_len = 8;
642 char a_str[cstring_len + 1];
643 char b_str[cstring_len + 1];
648 git_oid_tostr( b_str, cstring_len, aSecond );
650#if ( LIBGIT2_VER_MAJOR >= 1 ) || ( LIBGIT2_VER_MINOR >= 99 )
651 if( !git_oid_is_zero( aFirst ) )
653 if( !git_oid_iszero( aFirst ) )
656 git_oid_tostr( a_str, cstring_len, aFirst );
657 status = wxString::Format(
_(
"* [updated] %s..%s %s" ), a_str, b_str, aRefname );
661 status = wxString::Format(
_(
"* [new] %s %s" ), b_str, aRefname );
673 int64_t progress = 100;
678 progress = ( aCurrent * 100 ) / aTotal;
681 wxString progressMessage = wxString::Format(
_(
"Writing objects: %d%% (%d/%d), %d bytes" ),
682 progress, aCurrent, aTotal, aBytes );
692 wxString status( aStatus );
694 if( !status.IsEmpty() )
696 wxString statusMessage = wxString::Format(
_(
"* [rejected] %s (%s)" ), aRefname, aStatus );
701 wxString statusMessage = wxString::Format(
_(
"[updated] %s" ), aRefname );
709extern "C" int credentials_cb( git_cred** aOut,
const char* aUrl,
const char* aUsername,
710 unsigned int aAllowedTypes,
void* aPayload )
715 return GIT_PASSTHROUGH;
717 if( aAllowedTypes & GIT_CREDTYPE_USERNAME
718 && !( parent->
TestedTypes() & GIT_CREDTYPE_USERNAME ) )
720 wxString username = parent->
GetUsername().Trim().Trim(
false );
721 git_cred_username_new( aOut, username.ToStdString().c_str() );
725 && ( aAllowedTypes & GIT_CREDTYPE_USERPASS_PLAINTEXT )
726 && !( parent->
TestedTypes() & GIT_CREDTYPE_USERPASS_PLAINTEXT ) )
728 wxString username = parent->
GetUsername().Trim().Trim(
false );
729 wxString password = parent->
GetPassword().Trim().Trim(
false );
731 git_cred_userpass_plaintext_new( aOut, username.ToStdString().c_str(),
732 password.ToStdString().c_str() );
733 parent->
TestedTypes() |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
736 && ( aAllowedTypes & GIT_CREDTYPE_SSH_KEY )
737 && !( parent->
TestedTypes() & GIT_CREDTYPE_SSH_KEY ) )
742 if( sshKey.IsEmpty() )
745 return GIT_PASSTHROUGH;
748 wxString sshPubKey = sshKey +
".pub";
749 wxString username = parent->
GetUsername().Trim().Trim(
false );
750 wxString password = parent->
GetPassword().Trim().Trim(
false );
752 git_cred_ssh_key_new( aOut, username.ToStdString().c_str(),
753 sshPubKey.ToStdString().c_str(),
754 sshKey.ToStdString().c_str(),
755 password.ToStdString().c_str() );
759 return GIT_PASSTHROUGH;
std::vector< wxString > GetBranchNames() const
void updateConnectionType()
wxString GetCurrentBranchName() 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)