X-Git-Url: http://git.sourceforge.jp/view?p=tortoisegit%2FTortoiseGitJp.git;a=blobdiff_plain;f=src%2FGit%2FGit.cpp;h=6dd0ad8ce9cf2f1fddd52b845eddd2aa4781a099;hp=387b4911b795818fb3bd8343a733b03ef0ee6541;hb=69ec9a5aa2167fb45503825cc55de0fd49ab97c0;hpb=59859ba884bbf26473b807ab7c6a0439965968f4 diff --git a/src/Git/Git.cpp b/src/Git/Git.cpp index 387b491..6dd0ad8 100644 --- a/src/Git/Git.cpp +++ b/src/Git/Git.cpp @@ -5,12 +5,184 @@ #include "registry.h" #include "GitConfig.h" + +static LPTSTR nextpath(LPCTSTR src, LPTSTR dst, UINT maxlen) +{ + LPCTSTR orgsrc; + + while (*src == _T(';')) + src++; + + orgsrc = src; + + if (!--maxlen) + goto nullterm; + + while (*src && *src != _T(';')) + { + if (*src != _T('"')) + { + *dst++ = *src++; + if (!--maxlen) + { + orgsrc = src; + goto nullterm; + } + } + else + { + src++; + while (*src && *src != _T('"')) + { + *dst++ = *src++; + if (!--maxlen) + { + orgsrc = src; + goto nullterm; + } + } + + if (*src) + src++; + } + } + + while (*src == _T(';')) + src++; + +nullterm: + + *dst = 0; + + return (orgsrc != src) ? (LPTSTR)src : NULL; +} + +static inline BOOL FileExists(LPCTSTR lpszFileName) +{ + struct _stat st; + return _tstat(lpszFileName, &st) == 0; +} + +static BOOL FindGitPath() +{ + size_t size; + _tgetenv_s(&size, NULL, 0, _T("PATH")); + + if (!size) + { + return FALSE; + } + + TCHAR *env = (TCHAR*)alloca(size * sizeof(TCHAR)); + _tgetenv_s(&size, env, size, _T("PATH")); + + TCHAR buf[_MAX_PATH]; + + // search in all paths defined in PATH + while ((env = nextpath(env, buf, _MAX_PATH-1)) && *buf) + { + TCHAR *pfin = buf + _tcslen(buf)-1; + + // ensure trailing slash + if (*pfin != _T('/') && *pfin != _T('\\')) + _tcscpy(++pfin, _T("\\")); + + const int len = _tcslen(buf); + + if ((len + 7) < _MAX_PATH) + _tcscpy(pfin+1, _T("git.exe")); + else + break; + + if ( FileExists(buf) ) + { + // dir found + return TRUE; + } + } + + return FALSE; +} + + #define MAX_DIRBUFFER 1000 +#define CALL_OUTPUT_READ_CHUNK_SIZE 1024 + CString CGit::ms_LastMsysGitDir; CGit g_Git; +BOOL g_IsWingitDllload = TRUE; + +LPBYTE wgGetRevisionID_safe(const char *pszProjectPath, const char *pszName) +{ + if(g_IsWingitDllload) + return wgGetRevisionID(pszProjectPath,pszName); + else + return NULL; +} + +BOOL wgEnumFiles_safe(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData) +{ + if(g_IsWingitDllload) + return wgEnumFiles(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData); + else + return FALSE; +} + +BOOL CGit::IsVista() +{ + + if( CRegStdWORD(_T("Software\\TortoiseGit\\CacheType") ) == 0) + { + g_IsWingitDllload=FALSE; + return TRUE; + } + + OSVERSIONINFO osvi; + BOOL bIsWindowsXPorLater; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + GetVersionEx(&osvi); + + if(osvi.dwMajorVersion >= 6) + return TRUE; + else + return FALSE; +} + +static void InitWinGitDll() +{ + __try + { + + if( CGit::IsVista () ) + { + g_IsWingitDllload=FALSE; + return; + } + if ( !wgInit() ) + { + // TODO + } + } + __except(1) + { + g_IsWingitDllload=FALSE; + return; + } + +} CGit::CGit(void) { GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER)); + m_CurrentDir.ReleaseBuffer(); + // make sure git/bin is in PATH before wingit.dll gets (delay) loaded by wgInit() + if ( !CheckMsysGitDir() ) + { + // TODO + } + InitWinGitDll(); } CGit::~CGit(void) @@ -74,18 +246,23 @@ int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CStri } //Must use sperate function to convert ANSI str to union code string //Becuase A2W use stack as internal convert buffer. -void CGit::StringAppend(CString *str,BYTE *p,int code) +void CGit::StringAppend(CString *str,BYTE *p,int code,int length) { //USES_CONVERSION; //str->Append(A2W_CP((LPCSTR)p,code)); WCHAR * buf; - int len = strlen((const char*)p); + + int len ; + if(length<0) + len= strlen((const char*)p); + else + len=length; //if (len==0) // return ; //buf = new WCHAR[len*4 + 1]; buf = str->GetBuffer(len*4+1+str->GetLength())+str->GetLength(); SecureZeroMemory(buf, (len*4 + 1)*sizeof(WCHAR)); - MultiByteToWideChar(code, 0, (LPCSTR)p, -1, buf, len*4); + MultiByteToWideChar(code, 0, (LPCSTR)p, len, buf, len*4); str->ReleaseBuffer(); //str->Append(buf); //delete buf; @@ -104,20 +281,18 @@ BOOL CGit::IsInitRepos() return FALSE; } -int CGit::Run(CString cmd,BYTE_VECTOR *vector) +int CGit::Run(CGitCall* pcall) { PROCESS_INFORMATION pi; HANDLE hRead; - if(RunAsync(cmd,&pi,&hRead)) + if(RunAsync(pcall->GetCmd(),&pi,&hRead)) return GIT_ERROR_CREATE_PROCESS; DWORD readnumber; - BYTE data; - while(ReadFile(hRead,&data,1,&readnumber,NULL)) + BYTE data[CALL_OUTPUT_READ_CHUNK_SIZE]; + while(ReadFile(hRead,data,CALL_OUTPUT_READ_CHUNK_SIZE,&readnumber,NULL)) { - //g_Buffer[readnumber]=0; - vector->push_back(data); -// StringAppend(output,g_Buffer,codes); + pcall->OnOutputData(data,readnumber); } @@ -135,7 +310,25 @@ int CGit::Run(CString cmd,BYTE_VECTOR *vector) CloseHandle(hRead); return exitcode; +} +class CGitCall_ByteVector : public CGitCall +{ +public: + CGitCall_ByteVector(CString cmd,BYTE_VECTOR* pvector):CGitCall(cmd),m_pvector(pvector){} + virtual bool OnOutputData(const BYTE* data, size_t size) + { + size_t oldsize=m_pvector->size(); + m_pvector->resize(m_pvector->size()+size); + memcpy(&*(m_pvector->begin()+oldsize),data,size); + return false; + } + BYTE_VECTOR* m_pvector; +}; +int CGit::Run(CString cmd,BYTE_VECTOR *vector) +{ + CGitCall_ByteVector call(cmd,vector); + return Run(&call); } int CGit::Run(CString cmd, CString* output,int code) { @@ -143,13 +336,10 @@ int CGit::Run(CString cmd, CString* output,int code) int ret; ret=Run(cmd,&vector); - if(ret) - return ret; - vector.push_back(0); StringAppend(output,&(vector[0]),code); - return 0; + return ret; } CString CGit::GetUserName(void) @@ -226,6 +416,13 @@ int CGit::BuildOutputFormat(CString &format,bool IsFull) int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash, CTGitPath *path ,int count,int mask) { + CGitCall_ByteVector gitCall(CString(),&logOut); + return GetLog(&gitCall,hash,path,count,mask); +} + +//int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path ,int count,int mask) +int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path, int count, int mask) +{ CString cmd; CString log; @@ -262,9 +459,18 @@ int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash, CTGitPath *path ,int count if(mask& CGit::LOG_INFO_DETECT_RENAME ) param += _T(" -M "); + if(mask& CGit::LOG_INFO_FIRST_PARENT ) + param += _T(" --first-parent "); + + if(mask& CGit::LOG_INFO_NO_MERGE ) + param += _T(" --no-merges "); + + if(mask& CGit::LOG_INFO_FOLLOW) + param += _T(" --follow "); + param+=hash; - cmd.Format(_T("git.exe log %s -z --topo-order --parents %s --pretty=format:\""), + cmd.Format(_T("git.exe log %s -z --topo-order %s --parents --pretty=format:\""), num,param); BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH)); @@ -272,7 +478,10 @@ int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash, CTGitPath *path ,int count cmd += log; cmd += CString(_T("\" "))+hash+file; - return Run(cmd,&logOut); + pgitCall->SetCmd(cmd); + + return Run(pgitCall); +// return Run(cmd,&logOut); } #if 0 @@ -373,11 +582,13 @@ int CGit::RunLogFile(CString cmd,CString &filename) CloseHandle(pi.hProcess); CloseHandle(houtfile); return GIT_SUCCESS; - return 0; +// return 0; } git_revnum_t CGit::GetHash(CString &friendname) { + // NOTE: could replace this with wgGetRevisionID call + CString cmd; CString out; cmd.Format(_T("git.exe rev-parse %s" ),friendname); @@ -428,12 +639,12 @@ int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type) CString one; while( pos>=0 ) { - i++; one=output.Tokenize(_T("\n"),pos); list.push_back(one.Right(one.GetLength()-2)); if(one[0] == _T('*')) if(current) *current=i; + i++; } } return ret; @@ -497,72 +708,84 @@ int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map) BOOL CGit::CheckMsysGitDir() { - CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE,HKEY_LOCAL_MACHINE); - CString str=msysdir; - if(str.IsEmpty()) - { - CRegString msysinstalldir=CRegString(REG_MSYSGIT_INSTALL,_T(""),FALSE,HKEY_LOCAL_MACHINE); - str=msysinstalldir; - // check it has a trailing blank - if (str.Right(1) != "\\") - { - str += "\\"; - } - str+="bin"; - msysdir=str; - msysdir.write(); + static BOOL bInitialized = FALSE; + if (bInitialized) + { + return TRUE; } - //CGit::m_MsysGitPath=str; TCHAR *oldpath,*home; size_t size; - _tdupenv_s(&home,&size,_T("HOME")); - - if(home == NULL) - { + // set HOME if not set already + _tgetenv_s(&size, NULL, 0, _T("HOME")); + if (!size) + { _tdupenv_s(&home,&size,_T("USERPROFILE")); _tputenv_s(_T("HOME"),home); + free(home); } - free(home); - - //set path - _tdupenv_s(&oldpath,&size,_T("PATH")); - CString path; - CString unterminated_path = str; // path to msysgit without semicolon - CString oldpath_s = oldpath; - path.Format(_T("%s;"),str); - // check msysgit not already in path - if ( oldpath_s.Find( path ) < 0 && oldpath_s.Right( unterminated_path.GetLength() ) != unterminated_path ) + //setup ssh client + CRegString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH")); + CString ssh=sshclient; + + if(!ssh.IsEmpty()) + { + _tputenv_s(_T("GIT_SSH"),ssh); + }else + { + _tputenv_s(_T("GIT_SSH"),_T("")); + } + + // search PATH if git/bin directory is alredy present + if ( FindGitPath() ) + { + bInitialized = TRUE; + return TRUE; + } + + // add git/bin path to PATH + + CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE,HKEY_LOCAL_MACHINE); + CString str=msysdir; + if(str.IsEmpty()) { - // not already there, see if we have to take out one we added last time - if ( ms_LastMsysGitDir != "" ) + CRegString msysinstalldir=CRegString(REG_MSYSGIT_INSTALL,_T(""),FALSE,HKEY_LOCAL_MACHINE); + str=msysinstalldir; + if ( !str.IsEmpty() ) { - // we have added one so take it out - int index = oldpath_s.Find( ms_LastMsysGitDir ); - if ( index >= 0 ) - { - oldpath_s = oldpath_s.Left( index ) + - oldpath_s.Right( oldpath_s.GetLength() - (index+ms_LastMsysGitDir.GetLength()) ); - } + str += (str[str.GetLength()-1] != '\\') ? "\\bin" : "bin"; + msysdir=str; + msysdir.write(); + } + else + { + return false; } - // save the new msysdir path that we are about to add - ms_LastMsysGitDir = path; - // add the new one on the front of the existing path - path+=oldpath_s; - _tputenv_s(_T("PATH"),path); } + //CGit::m_MsysGitPath=str; + + //set path + + _tdupenv_s(&oldpath,&size,_T("PATH")); + + CString path; + path.Format(_T("%s;%s"),oldpath,str); + + _tputenv_s(_T("PATH"),path); + free(oldpath); - CString cmd,out; - cmd=_T("git.exe --version"); - if(g_Git.Run(cmd,&out,CP_UTF8)) + + if( !FindGitPath() ) { return false; } else + { + bInitialized = TRUE; return true; - -} \ No newline at end of file + } +}