#include "GitRev.h"\r
#include "registry.h"\r
#include "GitConfig.h"\r
+#include <map>\r
+#include "UnicodeUtils.h"\r
\r
\r
static LPTSTR nextpath(LPCTSTR src, LPTSTR dst, UINT maxlen)\r
\r
\r
#define MAX_DIRBUFFER 1000\r
+#define CALL_OUTPUT_READ_CHUNK_SIZE 1024\r
+\r
CString CGit::ms_LastMsysGitDir;\r
CGit g_Git;\r
-CGit::CGit(void)\r
+BOOL g_IsWingitDllload = TRUE;\r
+\r
+LPBYTE wgGetRevisionID_safe(const char *pszProjectPath, const char *pszName)\r
{\r
- GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));\r
+ //if(g_IsWingitDllload)\r
+ // return wgGetRevisionID(pszProjectPath,pszName);\r
+ //else\r
+ return NULL;\r
+}\r
\r
- // make sure git/bin is in PATH before wingit.dll gets (delay) loaded by wgInit()\r
- if ( !CheckMsysGitDir() )\r
+BOOL wgEnumFiles_safe(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)\r
+{\r
+ //if(g_IsWingitDllload)\r
+ // return wgEnumFiles(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData);\r
+ //else\r
+ // return g_Git.EnumFiles(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData);\r
+ return FALSE;\r
+}\r
+\r
+BOOL CGit::IsVista()\r
+{\r
+\r
+ if( CRegStdWORD(_T("Software\\TortoiseGit\\CacheType") ) == 0)\r
{\r
- // TODO\r
+ g_IsWingitDllload=FALSE;\r
+ return TRUE;\r
+ }\r
+\r
+ OSVERSIONINFO osvi;\r
+ BOOL bIsWindowsXPorLater;\r
+\r
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFO));\r
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r
+\r
+ GetVersionEx(&osvi);\r
+ \r
+ if(osvi.dwMajorVersion >= 6)\r
+ return TRUE;\r
+ else\r
+ return FALSE;\r
+}\r
+\r
+static void InitWinGitDll()\r
+{\r
+ __try\r
+ {\r
+\r
+ if( CGit::IsVista () )\r
+ {\r
+ g_IsWingitDllload=FALSE;\r
+ return;\r
+ }\r
+ if ( !wgInit() )\r
+ {\r
+ // TODO\r
+ }\r
+ }\r
+ __except(1)\r
+ {\r
+ g_IsWingitDllload=FALSE;\r
+ return;\r
}\r
\r
- if ( !wgInit() )\r
+}\r
+CGit::CGit(void)\r
+{\r
+#if 0\r
+ GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));\r
+ m_CurrentDir.ReleaseBuffer();\r
+ // make sure git/bin is in PATH before wingit.dll gets (delay) loaded by wgInit()\r
+ if ( !CheckMsysGitDir() )\r
{\r
// TODO\r
}\r
+ InitWinGitDll();\r
+#endif\r
}\r
\r
CGit::~CGit(void)\r
\r
return FALSE;\r
}\r
-int CGit::Run(CString cmd,BYTE_VECTOR *vector)\r
+int CGit::Run(CGitCall* pcall)\r
{\r
PROCESS_INFORMATION pi;\r
HANDLE hRead;\r
- if(RunAsync(cmd,&pi,&hRead))\r
+ if(RunAsync(pcall->GetCmd(),&pi,&hRead))\r
return GIT_ERROR_CREATE_PROCESS;\r
\r
DWORD readnumber;\r
- BYTE data;\r
- while(ReadFile(hRead,&data,1,&readnumber,NULL))\r
+ BYTE data[CALL_OUTPUT_READ_CHUNK_SIZE];\r
+ bool bAborted=false;\r
+ while(ReadFile(hRead,data,CALL_OUTPUT_READ_CHUNK_SIZE,&readnumber,NULL))\r
{\r
- //g_Buffer[readnumber]=0;\r
- vector->push_back(data);\r
-// StringAppend(output,g_Buffer,codes);\r
+ //Todo: when OnOutputData() returns 'true', abort git-command. Send CTRL-C signal?\r
+ if(!bAborted)//For now, flush output when command aborted.\r
+ if(pcall->OnOutputData(data,readnumber))\r
+ bAborted=true;\r
}\r
+ if(!bAborted)\r
+ pcall->OnEnd();\r
\r
\r
CloseHandle(pi.hThread);\r
\r
CloseHandle(hRead);\r
return exitcode;\r
+}\r
+class CGitCall_ByteVector : public CGitCall\r
+{\r
+public:\r
+ CGitCall_ByteVector(CString cmd,BYTE_VECTOR* pvector):CGitCall(cmd),m_pvector(pvector){}\r
+ virtual bool OnOutputData(const BYTE* data, size_t size)\r
+ {\r
+ size_t oldsize=m_pvector->size();\r
+ m_pvector->resize(m_pvector->size()+size);\r
+ memcpy(&*(m_pvector->begin()+oldsize),data,size);\r
+ return false;\r
+ }\r
+ BYTE_VECTOR* m_pvector;\r
\r
+};\r
+int CGit::Run(CString cmd,BYTE_VECTOR *vector)\r
+{\r
+ CGitCall_ByteVector call(cmd,vector);\r
+ return Run(&call);\r
}\r
int CGit::Run(CString cmd, CString* output,int code)\r
{\r
int ret;\r
ret=Run(cmd,&vector);\r
\r
- if(ret)\r
- return ret;\r
- \r
vector.push_back(0);\r
\r
StringAppend(output,&(vector[0]),code);\r
- return 0;\r
+ return ret;\r
}\r
\r
CString CGit::GetUserName(void)\r
\r
int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash, CTGitPath *path ,int count,int mask)\r
{\r
+ CGitCall_ByteVector gitCall(CString(),&logOut);\r
+ return GetLog(&gitCall,hash,path,count,mask);\r
+}\r
+\r
+//int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path ,int count,int mask)\r
+int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path, int count, int mask)\r
+{\r
\r
CString cmd;\r
CString log;\r
if(mask& CGit::LOG_INFO_DETECT_RENAME )\r
param += _T(" -M ");\r
\r
+ if(mask& CGit::LOG_INFO_FIRST_PARENT )\r
+ param += _T(" --first-parent ");\r
+ \r
+ if(mask& CGit::LOG_INFO_NO_MERGE )\r
+ param += _T(" --no-merges ");\r
+\r
+ if(mask& CGit::LOG_INFO_FOLLOW)\r
+ param += _T(" --follow ");\r
+\r
param+=hash;\r
\r
- cmd.Format(_T("git.exe log %s -z --topo-order --parents %s --pretty=format:\""),\r
+ cmd.Format(_T("git.exe log %s -z --topo-order %s --parents --pretty=format:\""),\r
num,param);\r
\r
BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH));\r
cmd += log;\r
cmd += CString(_T("\" "))+hash+file;\r
\r
- return Run(cmd,&logOut);\r
+ pgitCall->SetCmd(cmd);\r
+\r
+ return Run(pgitCall);\r
+// return Run(cmd,&logOut);\r
}\r
\r
#if 0\r
CloseHandle(pi.hProcess);\r
CloseHandle(houtfile);\r
return GIT_SUCCESS;\r
- return 0;\r
+// return 0;\r
}\r
\r
git_revnum_t CGit::GetHash(CString &friendname)\r
CString one;\r
while( pos>=0 )\r
{\r
- i++;\r
one=output.Tokenize(_T("\n"),pos);\r
list.push_back(one.Right(one.GetLength()-2));\r
if(one[0] == _T('*'))\r
if(current)\r
*current=i;\r
+ i++;\r
}\r
}\r
return ret;\r
free(home);\r
}\r
\r
+ //setup ssh client\r
+ CRegString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH"));\r
+ CString ssh=sshclient;\r
+\r
+ if(!ssh.IsEmpty())\r
+ {\r
+ _tputenv_s(_T("GIT_SSH"),ssh);\r
+ }else\r
+ {\r
+ _tputenv_s(_T("GIT_SSH"),_T(""));\r
+ }\r
+\r
// search PATH if git/bin directory is alredy present\r
if ( FindGitPath() )\r
{\r
\r
free(oldpath);\r
\r
- if( !FindGitPath() )\r
+\r
+ if( !FindGitPath() )\r
{\r
return false;\r
}\r
bInitialized = TRUE;\r
return true;\r
}\r
-}
\ No newline at end of file
+}\r
+\r
+\r
+class CGitCall_EnumFiles : public CGitCall\r
+{\r
+public:\r
+ CGitCall_EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)\r
+ : m_pszProjectPath(pszProjectPath),\r
+ m_pszSubPath(pszSubPath),\r
+ m_nFlags(nFlags),\r
+ m_pEnumCb(pEnumCb),\r
+ m_pUserData(pUserData)\r
+ {\r
+ }\r
+\r
+ typedef std::map<CStringA,char> TStrCharMap;\r
+\r
+ const char * m_pszProjectPath;\r
+ const char * m_pszSubPath;\r
+ unsigned int m_nFlags;\r
+ WGENUMFILECB * m_pEnumCb;\r
+ void * m_pUserData;\r
+\r
+ BYTE_VECTOR m_DataCollector;\r
+ TStrCharMap m_FileStatus;\r
+\r
+ virtual bool OnOutputData(const BYTE* data, size_t size)\r
+ {\r
+ m_DataCollector.append(data,size);\r
+ while(true)\r
+ {\r
+ int found=m_DataCollector.findData((const BYTE*)"\n",1);\r
+ if(found<0)\r
+ return false;\r
+ CStringA line;\r
+ char* pline=line.GetBuffer(found+1);\r
+ memcpy(pline,&*m_DataCollector.begin(),found);\r
+ pline[found]='\0';\r
+ line.ReleaseBuffer();\r
+ OnSingleLine(line);\r
+ m_DataCollector.erase(m_DataCollector.begin(),m_DataCollector.begin()+found+1);\r
+ }\r
+ return false;//Should never reach this\r
+ }\r
+ virtual void OnEnd()\r
+ {\r
+ for(TStrCharMap::iterator itFileStatus=m_FileStatus.begin();itFileStatus!=m_FileStatus.end();++itFileStatus)\r
+ {\r
+ wgFile_s fileStatus;\r
+ fileStatus.sFileName=itFileStatus->first;\r
+ switch(itFileStatus->second)\r
+ {\r
+ case 'C': fileStatus.nStatus=WGFS_Modified;break;\r
+ case 'H': fileStatus.nStatus=WGFS_Normal;break;\r
+ case 'R': fileStatus.nStatus=WGFS_Deleted;break;\r
+ case '?': fileStatus.nStatus=WGFS_Empty;break;//Other?\r
+ case 'K'://Todo: Killed?\r
+ case 'M'://Todo: What to do with this state? WGFS_Conflicted?\r
+ default://Unexpected status. Show as normal.\r
+ fileStatus.nStatus=WGFS_Normal;\r
+ }\r
+ fileStatus.sha1=NULL;//Unknown with this call\r
+ fileStatus.nFlags=0;//Never a directory with this call. Git doesnt track directories as such.\r
+ (*m_pEnumCb)(&fileStatus,m_pUserData);\r
+ }\r
+ }\r
+ bool OnSingleLine(CStringA line)\r
+ {\r
+ //Parse single line\r
+ int space=line.Find(' ');\r
+ if(space<0)\r
+ return false;\r
+ char status=line[0];\r
+ CStringA path=line;\r
+ path=path.Mid(space+1);\r
+ m_FileStatus[path]=status;\r
+ return true;\r
+ }\r
+\r
+\r
+\r
+\r
+};\r
+\r
+BOOL CGit::EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)\r
+{\r
+ if(*pszProjectPath=='\0')\r
+ return FALSE;\r
+ CGitCall_EnumFiles W_GitCall(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData);\r
+ CString cmd;\r
+\r
+/* char W_szToDir[MAX_PATH];\r
+ strncpy(W_szToDir,pszProjectPath,sizeof(W_szToDir)-1);\r
+ if(W_szToDir[strlen(W_szToDir)-1]!='\\')\r
+ strncat(W_szToDir,"\\",sizeof(W_szToDir)-1);\r
+\r
+ SetCurrentDirectoryA(W_szToDir);\r
+ GetCurrentDirectoryA(sizeof(W_szToDir)-1,W_szToDir);\r
+*/\r
+ SetCurrentDir(CUnicodeUtils::GetUnicode(pszProjectPath));\r
+ cmd.Format(_T("git.exe ls-files -t -c -d -m"));// -- %s"),CUnicodeUtils::GetUnicode(pszProjectPath));\r
+ W_GitCall.SetCmd(cmd);\r
+ Run(&W_GitCall);\r
+ return TRUE;\r
+}\r