1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include <CrySystem/File/CryFile.h>
5 #include "PerforceSourceControl.h"
6 #include "PasswordDlg.h"
7 #include <CryCore/Platform/platform_impl.inl>
8 #include <CryThreading/IThreadManager.h>
11 #include <EditorFramework/TrayArea.h>
13 #include <Controls/QPopupWidget.h>
16 #include <QHBoxLayout>
17 #include <QVBoxLayout>
23 extern CPerforceSourceControl
* g_pPerforceControl
;
25 REGISTER_TRAY_AREA_WIDGET(CPerforceTrayWidget
, 100)
27 class PerforceSettings
: public QWidget
30 PerforceSettings(QWidget
* pParent
= nullptr)
32 QHBoxLayout
* pMainLayout
= new QHBoxLayout();
34 m_pLabelLayout
= new QVBoxLayout();
35 m_pInputLayout
= new QVBoxLayout();
36 pMainLayout
->addLayout(m_pLabelLayout
);
37 pMainLayout
->addLayout(m_pInputLayout
);
39 m_pLabelLayout
->addWidget(new QLabel("Online"));
40 m_pConnectionCheckBox
= new QCheckBox();
41 m_pConnectionCheckBox
->setChecked(!g_pPerforceControl
->IsWorkOffline());
42 connect(m_pConnectionCheckBox
, &QCheckBox::toggled
, [this](bool bChecked
)
44 g_pPerforceControl
->SetWorkOffline(!bChecked
);
45 m_pServerInput
->setEnabled(bChecked
);
46 m_pUserInput
->setEnabled(bChecked
);
47 m_pWorkspaceInput
->setEnabled(bChecked
);
48 m_pPasswordInput
->setEnabled(bChecked
);
51 m_pInputLayout
->addWidget(m_pConnectionCheckBox
);
53 CMyClientApi
& clientApi
= g_pPerforceControl
->GetClientApi();
54 m_pServerInput
= CreateSection("Server", clientApi
.GetPort().Value());
55 m_pUserInput
= CreateSection("User", clientApi
.GetUser().Value());
56 m_pWorkspaceInput
= CreateSection("Workspace", clientApi
.GetClient().Value());
57 m_pPasswordInput
= CreateSection("Password", clientApi
.GetPassword().Value(), true);
59 g_pPerforceControl
->signalWorkOfflineChanged
.Connect(this, &PerforceSettings::OnConnectionStatusChanged
);
61 setLayout(pMainLayout
);
65 QLineEdit
* CreateSection(const char* szLabel
, const char* szInput
, bool bIsPassword
= false)
67 m_pLabelLayout
->addWidget(new QLabel(szLabel
));
68 QLineEdit
* pLineEdit
= new QLineEdit();
70 pLineEdit
->setEchoMode(QLineEdit::Password
);
71 pLineEdit
->setText(szInput
);
72 connect(pLineEdit
, &QLineEdit::textChanged
, this, &PerforceSettings::OnSettingsChanged
);
73 m_pInputLayout
->addWidget(pLineEdit
);
78 void OnConnectionStatusChanged()
80 m_pConnectionCheckBox
->setChecked(!g_pPerforceControl
->IsWorkOffline());
83 void OnSettingsChanged() const
85 CMyClientApi
& clientApi
= g_pPerforceControl
->GetClientApi();
87 clientApi
.DefinePassword(m_pPasswordInput
->text().toLocal8Bit(), &e
);
88 clientApi
.DefineClient(m_pWorkspaceInput
->text().toLocal8Bit(), &e
);
89 clientApi
.DefinePort(m_pServerInput
->text().toLocal8Bit(), &e
);
90 clientApi
.DefineUser(m_pUserInput
->text().toLocal8Bit(), &e
);
94 QVBoxLayout
* m_pLabelLayout
;
95 QVBoxLayout
* m_pInputLayout
;
97 QCheckBox
* m_pConnectionCheckBox
;
98 QLineEdit
* m_pServerInput
;
99 QLineEdit
* m_pUserInput
;
100 QLineEdit
* m_pWorkspaceInput
;
101 QLineEdit
* m_pPasswordInput
;
104 CPerforceTrayWidget::CPerforceTrayWidget(QWidget
* pParent
/*= nullptr*/)
106 CMyClientApi
& clientApi
= g_pPerforceControl
->GetClientApi();
107 m_pPopUpMenu
= new QPopupWidget("PerforceSettingsPopUp", QtUtil::MakeScrollable(new PerforceSettings()), QSize(340, 150), true);
108 m_pPopUpMenu
->SetFocusShareWidget(this);
109 connect(this, &QToolButton::clicked
, this, &CPerforceTrayWidget::OnClicked
);
110 g_pPerforceControl
->signalWorkOfflineChanged
.Connect(this, &CPerforceTrayWidget::OnConnectionStatusChanged
);
111 OnConnectionStatusChanged();
114 void CPerforceTrayWidget::OnConnectionStatusChanged()
116 CryIconColorMap colorMap
;
117 colorMap
[QIcon::Selected
] = QColor(125, 198, 83);
118 if (!g_pPerforceControl
->IsWorkOffline())
119 setIcon(CryIcon("icons:p4.ico", colorMap
).pixmap(24, 24, QIcon::Normal
, QIcon::On
));
121 setIcon(CryIcon("icons:p4.ico"));
124 void CPerforceTrayWidget::OnClicked(bool bChecked
)
126 if (m_pPopUpMenu
->isVisible())
128 m_pPopUpMenu
->hide();
132 m_pPopUpMenu
->ShowAt(mapToGlobal(QPoint(width(), height())));
137 CryCriticalSection g_cPerforceValues
;
140 struct CPerforceThread
: public IThread
142 const char* m_filename
;
143 CPerforceSourceControl
* m_pSourceControl
;
145 CPerforceThread(CPerforceSourceControl
* pSourceControl
, const char* filename
)
147 m_pSourceControl
= pSourceControl
;
148 m_filename
= filename
;
151 virtual ~CPerforceThread()
153 gEnv
->pThreadManager
->JoinThread(this, eJM_Join
);
158 // Start accepting work on thread
159 virtual void ThreadEntry()
161 m_pSourceControl
->GetFileAttributesThread(m_filename
);
165 void CMyClientUser::HandleError(Error
* e
)
170 if ( strstr( m.Text(), "file(s) not in client view." ) )
172 else if ( strstr( m.Text(), "no such file(s)" ) )
174 else if ( strstr( m.Text(), "access denied" ) )
180 void CMyClientUser::Init()
182 m_bIsClientUnknown
= false;
184 m_bIsPreCreateFile
= false;
190 void CMyClientUser::PreCreateFileName(const char* file
)
192 m_bIsPreCreateFile
= true;
193 cry_strcpy(m_file
, file
);
197 void CMyClientUser::OutputStat(StrDict
* varList
)
199 if (m_bIsSetup
&& !m_bIsPreCreateFile
)
208 m_lockStatus
= SCC_LOCK_STATUS_UNLOCKED
;
210 for (int i
= 0; varList
->GetVar(i
, var
, val
); i
++)
212 if (m_bIsPreCreateFile
)
214 if (var
== "clientFile")
216 char tmpval
[MAX_PATH
];
217 cry_strcpy(tmpval
, val
.Text());
219 while (ch
= strchr(ch
, '/'))
222 if (!stricmp(tmpval
, m_file
))
224 cry_strcpy(m_findedFile
, val
.Text());
225 m_bIsPreCreateFile
= false;
232 cry_strcpy(m_action
, val
.Text());
233 else if (var
== "headAction")
234 cry_strcpy(m_headAction
, val
.Text());
235 else if (var
== "headRev")
237 cry_strcpy(m_clientHasLatestRev
, val
.Text());
238 m_nFileHeadRev
= val
.Atoi64();
240 else if (!strncmp(var
.Text(), "otherAction", 11) && !strcmp(val
.Text(), "edit"))
241 cry_strcpy(m_otherAction
, val
.Text());
242 else if (var
== "haveRev")
244 if (val
!= m_clientHasLatestRev
)
245 m_clientHasLatestRev
[0] = 0;
246 m_nFileHaveRev
= val
.Atoi64();
248 else if (var
== "depotFile")
249 cry_strcpy(m_depotFile
, val
.Text());
250 else if (var
== "otherOpen0")
251 cry_strcpy(m_otherUser
, val
.Text());
252 else if (!strncmp(var
.Text(), "otherLock0", 10))
254 m_lockStatus
= SCC_LOCK_STATUS_LOCKED_BY_OTHERS
;
255 cry_strcpy(m_lockedBy
, val
.Text());
257 else if (var
== "ourLock")
258 m_lockStatus
= SCC_LOCK_STATUS_LOCKED_BY_US
;
264 void CMyClientUser::OutputInfo(char level
, const char* data
)
266 m_output
.Append(data
);
268 string
strData(data
);
269 if ("Client unknown." == strData
)
271 m_bIsClientUnknown
= true;
276 string var
= strData
.Tokenize(":", nStart
);
278 if (!var
.IsEmpty() && nStart
> 1)
279 val
= strData
.Mid(nStart
).Trim(" ");
281 if ("Client root" == var
)
283 else if ("Client host" == var
)
285 else if ("Client name" == var
)
287 else if ("Current directory" == var
)
288 m_currentDirectory
= val
;
290 if (!m_bIsPreCreateFile
)
293 const char* ch
= strrchr(data
, '/');
296 if (!stricmp(ch
+ 1, m_file
))
298 cry_strcpy(m_findedFile
, ch
+ 1);
299 m_bIsPreCreateFile
= false;
304 void CMyClientUser::InputData(StrBuf
* buf
, Error
* e
)
306 if (m_bIsCreatingChangelist
)
310 void CMyClientUser::Edit(FileSys
* f1
, Error
* e
)
315 char* src
= &msrc
[0];
316 char* dst
= &mdst
[0];
318 f1
->Open(FOM_READ
, e
);
319 int size
= f1
->Read(msrc
, 10240, e
);
325 if (!strnicmp(src
, "\nDescription", 11))
328 while (*src
!= '\n' && *src
!= '\0')
331 while (*src
!= '\n' && *src
!= '\0')
333 strcpy(dst
, "\nDescription:\n\t");
336 dst
+= strlen(m_desc
);
337 strcpy(dst
, " (by Perforce Plug-in)");
347 f1
->Open(FOM_WRITE
, e
);
348 f1
->Write(mdst
, strlen(mdst
), e
);
351 cry_strcpy(m_desc
, m_initDesc
);
354 ////////////////////////////////////////////////////////////
356 void CMyClientApi::Run(const char* func
)
358 // The "enableStreams" var has to be set prior to any Run call in order to be able to support Perforce streams
359 ClientApi::SetVar("enableStreams");
360 ClientApi::Run(func
);
363 void CMyClientApi::Run(const char* func
, ClientUser
* ui
)
365 ClientApi::SetVar("enableStreams");
366 ClientApi::Run(func
, ui
);
369 ////////////////////////////////////////////////////////////
371 CPerforceSourceControl::CPerforceSourceControl() : m_ref(0)
374 m_bIsWorkOffline
= false;
375 m_bIsFailConnectionLogged
= false;
376 m_dwLastAccessTime
= 0;
377 m_isSecondThread
= false;
379 InitCommonControls();
382 CPerforceSourceControl::~CPerforceSourceControl()
386 gEnv
->pThreadManager
->JoinThread(m_thread
, eJM_Join
);
391 bool CPerforceSourceControl::Connect()
396 SetWorkOffline(true);
397 if (!m_bIsFailConnectionLogged
)
399 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_ERROR
, "\nPerforce plugin: Failed to connect.");
400 m_bIsFailConnectionLogged
= true;
406 CryLog("\nPerforce plugin: Connected.");
407 m_bIsFailConnectionLogged
= false;
412 bool CPerforceSourceControl::Reconnect()
414 if (m_client
.Dropped())
416 if (!m_bIsFailConnectionLogged
)
418 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_ERROR
, "\nPerforce connection dropped: attempting reconnect");
423 SetWorkOffline(true);
430 void CPerforceSourceControl::FreeData()
432 m_client
.Final(&m_e
);
436 void CPerforceSourceControl::Init()
444 ConvertFileNameCS doesn't seem to do any conversion.
446 First it checks if the path is available on local HDD, then if it hasn't found
447 the path locally it looks in perforce (passing in local paths to P4v's API).
449 The path stored in sDst is the location which either exists and was found, or
450 will exist once you get latest...
452 If the file neither exists locally or in the depot, sDst will be as far as exists in Perforce...
453 Why is this a problem? Well, if you called GetFileAttributes on a file that doesn't exist in P4V
454 you'll be given the attributes for the deepest folder of the path you provided which exists on
455 your local machine - which is probably why you're here reading this comment :)
458 void CPerforceSourceControl::ConvertFileNameCS(char* sDst
, const char* sSrcFilename
)
463 char szAdjustedFile
[ICryPak::g_nMaxPath
];
464 cry_strcpy(szAdjustedFile
, sSrcFilename
);
469 char csPath
[ICryPak::g_nMaxPath
] = { 0 };
473 ch
= strrchr(szAdjustedFile
, '\\');
474 ch1
= strrchr(szAdjustedFile
, '/');
475 if (ch
< ch1
) ch
= ch1
;
476 bool bIsFirstTime
= true;
478 bool bIsEndSlash
= false;
479 if (ch
&& ch
- szAdjustedFile
+ 1 == strlen(szAdjustedFile
))
485 //handle = gEnv->pCryPak->FindFirst( szAdjustedFile, &fd );
486 HANDLE handle
= FindFirstFile(szAdjustedFile
, &fd
);
488 if (handle
!= INVALID_HANDLE_VALUE
)
490 char tmp
[ICryPak::g_nMaxPath
];
491 cry_strcpy(tmp
, csPath
);
492 //cry_strcpy(csPath, fd.name);
493 cry_strcpy(csPath
, fd
.cFileName
);
495 cry_strcat(csPath
, "\\");
496 bIsFirstTime
= false;
497 cry_strcat(csPath
, tmp
);
499 //gEnv->pCryPak->FindClose( handle );
504 ch
= strrchr(szAdjustedFile
, '\\');
505 ch1
= strrchr(szAdjustedFile
, '/');
506 if (ch
< ch1
) ch
= ch1
;
512 cry_strcat(szAdjustedFile
, "\\");
513 cry_strcat(szAdjustedFile
, csPath
);
514 if (bIsEndSlash
|| strlen(szAdjustedFile
) < strlen(sSrcFilename
))
515 cry_strcat(szAdjustedFile
, "\\");
517 // if we have only folder on disk find in perforce
518 if (strlen(szAdjustedFile
) < strlen(sSrcFilename
))
520 if (IsFileManageable(szAdjustedFile
))
523 char clienFile
[MAX_PATH
] = { 0 };
528 cry_strcpy(file
, &sSrcFilename
[strlen(szAdjustedFile
)]);
529 char* ch
= strchr(file
, '/');
530 char* ch1
= strchr(file
, '\\');
531 if (ch
< ch1
) ch
= ch1
;
536 bFinded
= bCont
= FindDir(clienFile
, szAdjustedFile
, file
);
540 bFinded
= FindFile(clienFile
, szAdjustedFile
, file
);
543 cry_strcpy(szAdjustedFile
, clienFile
);
544 if (bCont
&& strlen(clienFile
) >= strlen(sSrcFilename
))
551 strcpy(sDst
, szAdjustedFile
);
554 void CPerforceSourceControl::MakePathCS(char* sDst
, const char* sSrcFilename
)
556 char szAdjustedFile
[ICryPak::g_nMaxPath
];
557 char szCheckedPath
[ICryPak::g_nMaxPath
];
558 cry_strcpy(szAdjustedFile
, sSrcFilename
);
560 char* ch
= &szAdjustedFile
[0];
564 char* ch1
= strchr(ch
, '/');
565 ch
= strchr(ch
, '\\');
567 if (ch1
&& ch
> ch1
) ch
= ch1
;
571 cry_strcpy(szCheckedPath
, szAdjustedFile
, ch
- szAdjustedFile
+ 1);
573 if (strlen(szCheckedPath
) == 3 && szCheckedPath
[1] == ':')
579 if (IsFileManageable(szCheckedPath
, false))
581 cry_strcpy(szAdjustedFile
, szCheckedPath
);
588 if (strlen(szAdjustedFile
) < strlen(sSrcFilename
))
590 if (IsFileManageable(szAdjustedFile
))
593 char clienFile
[MAX_PATH
] = { 0 };
598 cry_strcpy(file
, &sSrcFilename
[strlen(szAdjustedFile
)]);
599 char* ch
= strchr(file
, '/');
600 char* ch1
= strchr(file
, '\\');
601 if (ch
< ch1
) ch
= ch1
;
603 bool bFinded
= false;
608 bFinded
= bCont
= FindDir(clienFile
, szAdjustedFile
, file
);
613 strcpy(&szAdjustedFile
[strlen(szAdjustedFile
)], &sSrcFilename
[strlen(szAdjustedFile
)]);
617 cry_strcpy(szAdjustedFile
, clienFile
);
618 if (bCont
&& strlen(clienFile
) >= strlen(sSrcFilename
))
624 if (strlen(szAdjustedFile
) == strlen(sSrcFilename
))
625 strcpy(sDst
, szAdjustedFile
);
627 strcpy(sDst
, sSrcFilename
);
630 void CPerforceSourceControl::RenameFolders(const char* path
, const char* pathOld
)
632 const char* ch
= strchr(pathOld
, '\\');
634 ch
= strchr(ch
+ 1, '\\');
638 const char* const ch1
= strchr(ch
, '\\');
639 if (ch1
&& strncmp(ch
, &path
[ch
- pathOld
], ch1
- ch
))
641 char newpath
[ICryPak::g_nMaxPath
];
642 char newpathOld
[ICryPak::g_nMaxPath
];
643 cry_strcpy(newpath
, path
, (size_t)(ch1
- pathOld
));
644 cry_strcpy(newpathOld
, pathOld
, (size_t)(ch1
- pathOld
));
645 MoveFile(newpathOld
, newpath
);
651 bool CPerforceSourceControl::FindDir(char* clientFile
, const char* folder
, const char* dir
)
657 cry_strcpy(fl
, folder
);
659 char* argv
[] = { fl
};
660 m_ui
.PreCreateFileName(dir
);
662 m_client
.SetArgv(1, argv
);
663 m_client
.Run("dirs", &m_ui
);
669 strcpy(clientFile
, folder
);
670 strcat(clientFile
, m_ui
.m_findedFile
);
671 strcat(clientFile
, "\\");
672 if (*m_ui
.m_findedFile
)
678 bool CPerforceSourceControl::FindFile(char* clientFile
, const char* folder
, const char* file
)
683 char fullPath
[MAX_PATH
];
685 cry_strcpy(fullPath
, folder
);
686 cry_strcat(fullPath
, file
);
689 cry_strcpy(fl
, folder
);
691 char* argv
[] = { fl
};
692 m_ui
.PreCreateFileName(fullPath
);
694 m_client
.SetArgv(1, argv
);
695 m_client
.Run("fstat", &m_ui
);
701 strcpy(clientFile
, m_ui
.m_findedFile
);
708 bool CPerforceSourceControl::IsFileManageable(const char* sFilename
, bool bCheckFatal
)
716 if (m_bIsWorkOffline
)
720 cry_strcpy(fl
, sFilename
);
721 //ConvertFileNameCS(fl, sFilename);
723 char* argv
[] = { fl
};
724 Run("fstat", 1, argv
, true);
727 m_client
.SetArgv(1, argv
);
728 m_client
.Run("fstat", &m_ui
);
731 if (bCheckFatal
&& m_ui
.m_e
.IsFatal())
736 if (!fatal
&& !m_ui
.m_e
.IsError())
745 bool CPerforceSourceControl::IsFileExistsInDatabase(const char* sFilename
)
753 cry_strcpy(fl
, sFilename
);
754 char* argv
[] = { fl
};
756 m_client
.SetArgv(1, argv
);
757 m_client
.Run("fstat", &m_ui
);
760 if (!m_ui
.m_e
.Test())
762 if (strcmp(m_ui
.m_headAction
, "delete"))
768 // m_ui.m_e.Fmt(&errorMsg);
774 bool CPerforceSourceControl::IsFileCheckedOutByUser(const char* sFilename
, bool* pIsByAnotherUser
)
782 cry_strcpy(fl
, sFilename
);
783 char* argv
[] = { fl
};
785 m_client
.SetArgv(1, argv
);
786 m_client
.Run("fstat", &m_ui
);
789 if ((!strcmp(m_ui
.m_action
, "edit") || !strcmp(m_ui
.m_action
, "add")) && !m_ui
.m_e
.Test())
792 if (pIsByAnotherUser
)
794 *pIsByAnotherUser
= false;
795 if (!strcmp(m_ui
.m_otherAction
, "edit") && !m_ui
.m_e
.Test())
796 *pIsByAnotherUser
= true;
803 bool CPerforceSourceControl::IsFileLatestVersion(const char* sFilename
)
811 cry_strcpy(fl
, sFilename
);
812 char* argv
[] = { fl
};
814 m_client
.SetArgv(1, argv
);
815 m_client
.Run("fstat", &m_ui
);
818 if (m_ui
.m_clientHasLatestRev
[0] != 0)
824 uint32
CPerforceSourceControl::GetFileAttributesAndFileName(const char* filename
, char* FullFileName
)
826 // g_pSystem->GetILog()->Log("\n checking connection");
834 bool bCryFile
= file
.Open(filename
, "rb");
836 uint32 attributes
= 0;
838 char sFullFilenameLC
[MAX_PATH
];
839 GetCurrentDirectory(MAX_PATH
, sFullFilenameLC
);
840 cry_strcat(sFullFilenameLC
, "\\");
843 if (*sFullFilenameLC
&& !strnicmp(sFullFilenameLC
, filename
, strlen(sFullFilenameLC
)))
844 cry_strcpy(sFullFilenameLC
, file
.GetAdjustedFilename());
846 cry_strcat(sFullFilenameLC
, file
.GetAdjustedFilename());
849 cry_strcat(sFullFilenameLC
, filename
);
851 char sFullFilename
[ICryPak::g_nMaxPath
];
852 ConvertFileNameCS(sFullFilename
, sFullFilenameLC
);
855 strcpy(FullFileName
, sFullFilename
);
857 if (bCryFile
&& file
.IsInPak())
859 // g_pSystem->GetILog()->Log("\n file is in pak");
860 attributes
= SCC_FILE_ATTRIBUTE_READONLY
| SCC_FILE_ATTRIBUTE_INPAK
;
862 if (IsFileManageable(sFullFilename
) && IsFileExistsInDatabase(sFullFilename
))
864 // g_pSystem->GetILog()->Log("\n file is managable and also exists in the database");
865 attributes
|= SCC_FILE_ATTRIBUTE_MANAGED
;
866 bool isByAnotherUser
;
867 if (IsFileCheckedOutByUser(sFullFilename
, &isByAnotherUser
))
868 attributes
|= SCC_FILE_ATTRIBUTE_CHECKEDOUT
;
870 attributes
|= SCC_FILE_ATTRIBUTE_BYANOTHER
;
875 DWORD dwAttrib
= ::GetFileAttributes(sFullFilename
);
876 if (dwAttrib
!= INVALID_FILE_ATTRIBUTES
)
878 // g_pSystem->GetILog()->Log("\n we have valid file attributes");
879 attributes
= SCC_FILE_ATTRIBUTE_NORMAL
;
880 if (dwAttrib
& FILE_ATTRIBUTE_READONLY
)
881 attributes
|= SCC_FILE_ATTRIBUTE_READONLY
;
883 if (IsFileManageable(sFullFilename
))
885 // g_pSystem->GetILog()->Log("\n file is manageable");
886 if (IsFileExistsInDatabase(sFullFilename
))
888 attributes
|= SCC_FILE_ATTRIBUTE_MANAGED
;
889 // g_pSystem->GetILog()->Log("\n file exists in database");
890 bool isByAnotherUser
;
891 if (IsFileCheckedOutByUser(sFullFilename
, &isByAnotherUser
))
893 // g_pSystem->GetILog()->Log("\n file is checked out");
894 attributes
|= SCC_FILE_ATTRIBUTE_CHECKEDOUT
;
898 // g_pSystem->GetILog()->Log("\n by another user");
899 attributes
|= SCC_FILE_ATTRIBUTE_BYANOTHER
;
904 if (*sFullFilename
&& sFullFilename
[strlen(sFullFilename
) - 1] == '\\')
906 attributes
|= SCC_FILE_ATTRIBUTE_MANAGED
| SCC_FILE_ATTRIBUTE_FOLDER
;
913 // g_pSystem->GetILog()->Log("\n file has invalid file attributes");
914 if (!attributes
&& !bCryFile
)
916 if (IsFileManageable(sFullFilename
))
918 if (IsFileExistsInDatabase(sFullFilename
))
920 // g_pSystem->GetILog()->Log("\n file is managable and exists in the database");
921 attributes
= SCC_FILE_ATTRIBUTE_MANAGED
| SCC_FILE_ATTRIBUTE_NORMAL
| SCC_FILE_ATTRIBUTE_READONLY
;
922 bool isByAnotherUser
;
923 if (IsFileCheckedOutByUser(sFullFilename
, &isByAnotherUser
))
924 attributes
|= SCC_FILE_ATTRIBUTE_CHECKEDOUT
;
926 attributes
|= SCC_FILE_ATTRIBUTE_BYANOTHER
;
930 if (*sFullFilename
&& sFullFilename
[strlen(sFullFilename
) - 1] == '\\')
932 attributes
|= SCC_FILE_ATTRIBUTE_MANAGED
| SCC_FILE_ATTRIBUTE_FOLDER
;
938 if (!attributes
&& IsFolder(filename
, FullFileName
))
939 attributes
= SCC_FILE_ATTRIBUTE_FOLDER
;
941 if ((attributes
& SCC_FILE_ATTRIBUTE_FOLDER
) && FullFileName
)
942 strcat(FullFileName
, "...");
944 return attributes
? attributes
: SCC_FILE_ATTRIBUTE_INVALID
;
947 void CPerforceSourceControl::GetFileAttributesThread(const char* filename
)
949 uint32 unRetValue
= GetFileAttributesAndFileName(filename
, 0);
951 AUTO_LOCK(g_cPerforceValues
);
952 m_unRetValue
= unRetValue
;
956 uint32
CPerforceSourceControl::GetFileAttributes(const char* filename
)
958 //return GetFileAttributesAndFileName(filename, 0);
960 DWORD dwTime
= GetTickCount();
962 if (m_bIsWorkOffline
|| dwTime
- m_dwLastAccessTime
< 1000)
964 m_dwLastAccessTime
= dwTime
;
965 return GetFileAttributesAndFileName(filename
, 0);
968 m_isSkipThread
= false;
970 uint32 unRetValue
= SCC_FILE_ATTRIBUTE_INVALID
;
974 gEnv
->pThreadManager
->JoinThread(m_thread
, eJM_Join
);
978 m_isSecondThread
= true;
980 m_thread
= new CPerforceThread(this, filename
);
981 if (!gEnv
->pThreadManager
->SpawnThread(m_thread
, "PerforcePlugin"))
983 CryFatalError("Error spawning \"PerforcePlugin\" thread.");
986 DWORD dwWaitTime
= 10000; // 10 sec
987 DWORD dwCurTime
= dwTime
;
991 if (!m_isSkipThread
&& GetTickCount() - dwCurTime
> dwWaitTime
)
993 if (CryMessageBox(_T("Connection to Perforce is not responding. Do you want to switch to the offline mode?"), _T("Perforce Plug-in Error"), eMB_YesCancel
) == eQR_Yes
)
995 SetWorkOffline(true);
999 dwCurTime
= GetTickCount();
1000 dwWaitTime
= 10000; // 10 sec
1007 AUTO_LOCK(g_cPerforceValues
);
1008 unRetValue
= m_unRetValue
;
1013 m_isSecondThread
= false;
1014 m_dwLastAccessTime
= dwTime
;
1019 bool CPerforceSourceControl::IsFolder(const char* filename
, char* FullFileName
)
1021 bool bFolder
= false;
1023 char sFullFilename
[ICryPak::g_nMaxPath
];
1024 ConvertFileNameCS(sFullFilename
, filename
);
1026 uint32 attr
= ::GetFileAttributes(sFullFilename
);
1027 if (attr
== INVALID_FILE_ATTRIBUTES
)
1029 if (*sFullFilename
&& sFullFilename
[strlen(sFullFilename
) - 1] == '\\')
1034 else if ((attr
& FILE_ATTRIBUTE_DIRECTORY
))
1037 if (bFolder
&& FullFileName
)
1038 strcpy(FullFileName
, sFullFilename
);
1043 bool CPerforceSourceControl::DoesChangeListExist(const char* pDesc
, char* changeid
, int nLen
)
1050 char* argv
[] = { "-c", m_client
.GetClient().Text(), "-s", "pending", "-l" };
1052 m_client
.SetArgv(5, argv
);
1053 m_client
.Run("changes", &m_ui
);
1056 bool foundChange
= false;
1057 string
changes(m_ui
.m_output
);
1058 string
token("\r\n");
1060 string item
= changes
.Tokenize(token
, nStart
);
1061 while (!item
.IsEmpty())
1063 int idx
= item
.Find("Change ");
1066 int last
= item
.Find(" on ");
1067 int first
= item
.Find(" ");
1068 id
= item
.Left(last
);
1069 id
= id
.Right(id
.GetLength() - (first
+ 1));
1071 idx
= item
.Find(pDesc
);
1078 item
= changes
.Tokenize(token
, nStart
);
1081 m_ui
.m_output
.Empty();
1082 m_ui
.m_input
.Empty();
1084 if (!m_ui
.m_e
.Test() && !id
.IsEmpty() && foundChange
)
1086 cry_sprintf(changeid
, nLen
, "%s", id
.GetBuffer());
1093 bool CPerforceSourceControl::CreateChangeList(const char* pDesc
, char* changeid
, int nLen
)
1100 char* argv
[] = { "-o" };
1102 m_client
.SetArgv(1, argv
);
1103 m_client
.Run("change", &m_ui
);
1105 string
change(m_ui
.m_output
);
1107 description
.Format("%s", pDesc
);
1108 change
.Replace("<enter description here>", description
);
1110 string
files("Files:");
1111 int end
= change
.Find(files
.GetBuffer()) + files
.GetLength();
1112 int iFiles
= change
.Find(files
, end
);
1116 if (change
.GetLength() > end
)
1117 change
= change
.Left(end
);
1121 m_ui
.m_input
= change
;
1122 m_ui
.m_bIsCreatingChangelist
= true;
1123 char* argv2
[] = { "-i" };
1124 m_client
.SetArgv(1, argv2
);
1125 m_client
.Run("change", &m_ui
);
1126 m_ui
.m_bIsCreatingChangelist
= false;
1128 string
changeId(m_ui
.m_output
);
1129 int lastIdx
= changeId
.ReverseFind(' ');
1130 int firstIdx
= changeId
.Find(' ');
1131 string left
= changeId
.Left(lastIdx
);
1132 string
id(left
.Right(left
.GetLength() - (firstIdx
+ 1)));
1133 cry_sprintf(changeid
, nLen
, "%s", id
.GetBuffer());
1135 if (!m_ui
.m_e
.Test())
1141 bool CPerforceSourceControl::SubmitChangeList(char* changeid
)
1148 char* argv
[] = { "-c", changeid
};
1150 m_client
.SetArgv(2, argv
);
1151 m_client
.Run("submit", &m_ui
);
1153 if (!m_ui
.m_e
.Test())
1159 bool CPerforceSourceControl::DeleteChangeList(char* changeid
)
1166 char* argv
[] = { "-d", changeid
};
1168 m_client
.SetArgv(2, argv
);
1169 m_client
.Run("change", &m_ui
);
1171 if (!m_ui
.m_e
.Test())
1177 bool CPerforceSourceControl::Reopen(const char* filename
, char* changeid
)
1184 char FullFileName
[MAX_PATH
];
1185 string files
= filename
;
1187 string file
= files
.Tokenize(";", curPos
);
1188 for (; !file
.IsEmpty(); file
= files
.Tokenize(";", curPos
))
1190 if (file
.Trim().IsEmpty())
1192 uint32 attrib
= GetFileAttributesAndFileName(file
, FullFileName
);
1194 if ((attrib
!= SCC_FILE_ATTRIBUTE_INVALID
) && (attrib
& SCC_FILE_ATTRIBUTE_MANAGED
) && (attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
))
1196 char* argv
[] = { "-c", changeid
, FullFileName
};
1198 m_client
.SetArgv(3, argv
);
1199 m_client
.Run("reopen", &m_ui
);
1201 if (!m_ui
.m_e
.Test())
1209 bool CPerforceSourceControl::Add(const char* filename
, const char* desc
, int nFlags
, char* changelistId
)
1216 char FullFileName
[MAX_PATH
];
1217 string files
= filename
;
1219 string file
= files
.Tokenize(";", curPos
);
1220 for (; !file
.IsEmpty(); file
= files
.Tokenize(";", curPos
))
1222 if (file
.Trim().IsEmpty())
1224 uint32 attrib
= GetFileAttributesAndFileName(file
, FullFileName
);
1225 char sFullFilename
[ICryPak::g_nMaxPath
];
1226 if (attrib
& SCC_FILE_ATTRIBUTE_FOLDER
)
1228 cry_strcpy(sFullFilename
, filename
);
1229 cry_strcat(sFullFilename
, "*");
1233 MakePathCS(sFullFilename
, FullFileName
);
1234 if (strcmp(sFullFilename
, FullFileName
))
1235 RenameFolders(sFullFilename
, FullFileName
);
1238 if ((attrib
& SCC_FILE_ATTRIBUTE_FOLDER
) || ((attrib
!= SCC_FILE_ATTRIBUTE_INVALID
) && !(attrib
& SCC_FILE_ATTRIBUTE_MANAGED
) && IsFileManageable(sFullFilename
)))
1240 if (nFlags
& ADD_CHANGELIST
&& changelistId
)
1242 char* argv
[] = { "-c", changelistId
, sFullFilename
};
1244 m_client
.SetArgv(3, argv
);
1245 m_client
.Run("add", &m_ui
);
1247 if (desc
&& !(nFlags
& ADD_WITHOUT_SUBMIT
))
1249 cry_strcpy(m_ui
.m_desc
, desc
);
1251 m_client
.SetArgv(2, argv
);
1252 m_client
.Run("submit", &m_ui
);
1257 char* argv
[] = { sFullFilename
};
1259 m_client
.SetArgv(1, argv
);
1260 m_client
.Run("add", &m_ui
);
1262 if (desc
&& !(nFlags
& ADD_WITHOUT_SUBMIT
))
1264 cry_strcpy(m_ui
.m_desc
, desc
);
1266 m_client
.SetArgv(1, argv
);
1267 m_client
.Run("submit", &m_ui
);
1271 if (!m_ui
.m_e
.Test())
1279 bool CPerforceSourceControl::CheckIn(const char* filename
, const char* desc
, int nFlags
)
1286 char FullFileName
[MAX_PATH
];
1288 string files
= filename
;
1290 string file
= files
.Tokenize(";", curPos
);
1291 for (; !file
.IsEmpty(); file
= files
.Tokenize(";", curPos
))
1293 if (file
.Trim().IsEmpty())
1295 uint32 attrib
= GetFileAttributesAndFileName(file
, FullFileName
);
1297 if ((attrib
& SCC_FILE_ATTRIBUTE_FOLDER
) || ((attrib
!= SCC_FILE_ATTRIBUTE_INVALID
) && (attrib
& SCC_FILE_ATTRIBUTE_MANAGED
) && (attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
)))
1300 char* argv
[] = { "-c", "default", FullFileName
};
1301 m_client
.SetArgv(3, argv
);
1302 m_client
.Run("reopen", &m_ui
);
1306 cry_strcpy(m_ui
.m_desc
, desc
);
1308 char* argv
[] = { FullFileName
};
1309 m_client
.SetArgv(1, argv
);
1310 m_client
.Run("submit", &m_ui
);
1313 if (!m_ui
.m_e
.Test())
1321 bool CPerforceSourceControl::CheckOut(const char* filename
, int nFlags
, char* changelistId
)
1328 char FullFileName
[MAX_PATH
];
1330 string files
= filename
;
1332 string file
= files
.Tokenize(";", curPos
);
1333 for (; !file
.IsEmpty(); file
= files
.Tokenize(";", curPos
))
1335 if (file
.Trim().IsEmpty())
1337 uint32 attrib
= GetFileAttributesAndFileName(file
, FullFileName
);
1339 if ((attrib
& SCC_FILE_ATTRIBUTE_FOLDER
) || ((attrib
& SCC_FILE_ATTRIBUTE_MANAGED
) && !(attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
)))
1341 if (nFlags
& ADD_CHANGELIST
&& changelistId
)
1343 char* argv
[] = { "-c", changelistId
, FullFileName
};
1344 m_client
.SetArgv(3, argv
);
1345 m_client
.Run("edit", &m_ui
);
1349 char* argv
[] = { FullFileName
};
1350 m_client
.SetArgv(1, argv
);
1351 m_client
.Run("edit", &m_ui
);
1354 if (!m_ui
.m_e
.Test())
1361 bool CPerforceSourceControl::UndoCheckOut(const char* filename
, int nFlags
)
1368 char FullFileName
[MAX_PATH
];
1370 string files
= filename
;
1372 string file
= files
.Tokenize(";", curPos
);
1373 for (; !file
.IsEmpty(); file
= files
.Tokenize(";", curPos
))
1375 if (file
.Trim().IsEmpty())
1377 uint32 attrib
= GetFileAttributesAndFileName(file
, FullFileName
);
1379 if ((attrib
& SCC_FILE_ATTRIBUTE_FOLDER
) || ((attrib
& SCC_FILE_ATTRIBUTE_MANAGED
) && (attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
)))
1381 char* argv
[] = { FullFileName
};
1382 m_client
.SetArgv(1, argv
);
1383 m_client
.Run("revert", &m_ui
);
1384 if (!m_ui
.m_e
.Test())
1388 return true; // always return true to avoid error message box on folder operation
1391 bool CPerforceSourceControl::Rename(const char* filename
, const char* newname
, const char* desc
, int nFlags
)
1397 char FullFileName
[MAX_PATH
];
1398 uint32 attrib
= GetFileAttributesAndFileName(filename
, FullFileName
);
1400 if (!(attrib
& SCC_FILE_ATTRIBUTE_MANAGED
))
1403 if (attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
)
1404 UndoCheckOut(filename
, 0);
1406 //if(m_pIntegrator->FileCheckedOutByAnotherUser(FullFileName))
1409 char FullNewFileName
[MAX_PATH
];
1410 cry_strcpy(FullNewFileName
, newname
);
1413 char* argv
[] = { FullFileName
, FullNewFileName
};
1414 m_client
.SetArgv(2, argv
);
1415 m_client
.Run("integrate", &m_ui
);
1419 char* argv
[] = { FullFileName
};
1420 m_client
.SetArgv(1, argv
);
1421 m_client
.Run("delete", &m_ui
);
1424 cry_strcpy(m_ui
.m_desc
, desc
);
1426 char* argv
[] = { FullFileName
};
1427 m_client
.SetArgv(1, argv
);
1428 m_client
.Run("submit", &m_ui
);
1432 cry_strcpy(m_ui
.m_desc
, desc
);
1434 char* argv
[] = { FullNewFileName
};
1435 m_client
.SetArgv(1, argv
);
1436 m_client
.Run("submit", &m_ui
);
1439 if (!m_ui
.m_e
.Test())
1442 //p4 integrate source_file target_file
1443 //p4 delete source_file
1449 bool CPerforceSourceControl::Delete(const char* filename
, const char* desc
, int nFlags
, char* changelistId
/*= NULL*/)
1455 char FullFileName
[MAX_PATH
];
1456 uint32 attrib
= GetFileAttributesAndFileName(filename
, FullFileName
);
1458 if (!(attrib
& SCC_FILE_ATTRIBUTE_MANAGED
))
1461 if ((attrib
& SCC_FILE_ATTRIBUTE_MANAGED
) && (attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
))
1463 char* argv
[] = { FullFileName
};
1464 m_client
.SetArgv(1, argv
);
1465 m_client
.Run("revert", &m_ui
);
1468 if ((nFlags
& ADD_CHANGELIST
) && (changelistId
!= NULL
))
1470 char* argv
[] = { "-c", changelistId
, FullFileName
};
1471 m_client
.SetArgv(3, argv
);
1472 m_client
.Run("delete", &m_ui
);
1474 if (desc
&& !(nFlags
& DELETE_WITHOUT_SUBMIT
))
1476 cry_strcpy(m_ui
.m_desc
, desc
);
1477 m_client
.SetArgv(2, argv
);
1478 m_client
.Run("submit", &m_ui
);
1483 char* argv
[] = { FullFileName
};
1484 m_client
.SetArgv(1, argv
);
1485 m_client
.Run("delete", &m_ui
);
1487 if (desc
&& !(nFlags
& DELETE_WITHOUT_SUBMIT
))
1489 cry_strcpy(m_ui
.m_desc
, desc
);
1490 m_client
.SetArgv(1, argv
);
1491 m_client
.Run("submit", &m_ui
);
1495 if (!m_ui
.m_e
.Test())
1501 void CPerforceSourceControl::SetWorkOffline(bool bWorkOffline
)
1503 m_bIsWorkOffline
= bWorkOffline
;
1504 signalWorkOfflineChanged();
1507 void CPerforceSourceControl::ShowSettings()
1509 m_isSkipThread
= true;
1511 string
strPassword(m_client
.GetPassword().Value());
1512 string
strClient(m_client
.GetClient().Value());
1513 string
strUser(m_client
.GetUser().Value());
1514 string
strPort(m_client
.GetPort().Value());
1516 if (PerforceConnection::OpenPasswordDlg(strPort
, strUser
, strClient
, strPassword
, m_bIsWorkOffline
))
1519 m_client
.DefinePassword(strPassword
, &e
);
1520 m_client
.DefineClient(strClient
, &e
);
1521 m_client
.DefinePort(strPort
, &e
);
1522 m_client
.DefineUser(strUser
, &e
);
1527 const char* CPerforceSourceControl::GetErrorByGenericCode(int nGeneric
)
1532 return "Request is not consistent with documentation or cannot support a server version";
1534 return "Using unknown entity";
1536 return "Using entity in wrong context";
1538 return "Trying to do something you can't";
1540 return "Something must be corrected first";
1542 return "Operation was prevented by protection level";
1546 return "Action returned empty results";
1548 // not the fault of the user
1550 return "Inexplicable program fault";
1552 return "Client side program errors";
1554 return "Server administrative action required";
1556 return "Client configuration is inadequate";
1558 return "Client or server is too old to interact";
1560 return "Communication error";
1562 return "File is too big";
1568 bool CPerforceSourceControl::Run(const char* func
, int nArgs
, char* argv
[], bool bOnlyFatal
)
1570 for (int x
= 0; x
< nArgs
; ++x
)
1572 if (argv
[x
][0] == '\0')
1582 m_client
.SetArgv(nArgs
, argv
);
1583 m_client
.Run(func
, &m_ui
);
1586 #if 0 // connection debug
1587 for (int argid
= 0; argid
< nArgs
; argid
++)
1589 CryLog("\n arg %d : %s", argid
, argv
[argid
]);
1591 #endif // connection debug
1595 if (!m_ui
.m_e
.IsFatal())
1600 if (!m_ui
.m_e
.Test())
1604 if (m_ui
.m_e
.GetSeverity() == E_FAILED
|| m_ui
.m_e
.GetSeverity() == E_FATAL
)
1606 static int nGenericPrev
= 0;
1607 const int nGeneric
= m_ui
.m_e
.GetGeneric();
1609 if (IsSomeTimePassed())
1612 if (nGenericPrev
!= nGeneric
)
1614 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_ERROR
, "Perforce plugin: %s", GetErrorByGenericCode(nGeneric
));
1618 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_ERROR
, "Perforce plugin: %s", m
.Text());
1619 nGenericPrev
= nGeneric
;
1627 bool CPerforceSourceControl::CheckConnection()
1629 m_ui
.m_bIsClientUnknown
= false;
1632 if (!m_bIsWorkOffline
)
1634 bRet
= Run("info", 0, 0);
1637 if (m_bIsWorkOffline
)
1639 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_ERROR
, "Perforce plugin: Perforce is offline");
1643 if (m_ui
.m_bIsClientUnknown
|| m_ui
.m_clientRoot
.IsEmpty())
1646 errorMsg
.Format("Workspace %s for host %s is unknown. Check Perforce settings.", m_ui
.m_clientName
, m_ui
.m_clientHost
);
1647 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_ERROR
, string("Perforce plugin: ") + errorMsg
);
1650 else if (m_ui
.m_clientRoot
.CompareNoCase(m_ui
.m_currentDirectory
.Left(m_ui
.m_clientRoot
.GetLength())))
1653 errorMsg
.Format("Working folder (%s) is out of Perforce root (%s). Change Perforce settings or start Editor from %s...", m_ui
.m_currentDirectory
, m_ui
.m_clientRoot
, m_ui
.m_clientRoot
);
1654 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_ERROR
, string("Perforce plugin: ") + errorMsg
);
1660 bool CPerforceSourceControl::GetLatestVersion(const char* filename
, int nFlags
)
1666 char FullFileName
[MAX_PATH
];
1668 string files
= filename
;
1670 string file
= files
.Tokenize(";", curPos
);
1671 for (; !file
.IsEmpty(); file
= files
.Tokenize(";", curPos
))
1673 if (file
.Trim().IsEmpty())
1675 uint32 attrib
= GetFileAttributesAndFileName(file
, FullFileName
);
1677 if (!(attrib
& SCC_FILE_ATTRIBUTE_MANAGED
))
1680 if ((attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
) && ((nFlags
& GETLATEST_REVERT
) == 0))
1683 if (nFlags
& GETLATEST_REVERT
)
1685 char* argv
[] = { FullFileName
};
1686 m_client
.SetArgv(1, argv
);
1687 m_client
.Run("revert", &m_ui
);
1690 if (nFlags
& GETLATEST_ONLY_CHECK
)
1692 if (attrib
& SCC_FILE_ATTRIBUTE_FOLDER
)
1695 bRet
= IsFileLatestVersion(FullFileName
);
1699 char* argv
[] = { "-f", FullFileName
};
1700 m_client
.SetArgv(2, argv
);
1701 m_client
.Run("sync", &m_ui
);
1709 bool CPerforceSourceControl::GetInternalPath(const char* filename
, char* outPath
, int nOutPathSize
)
1711 if (!filename
|| !outPath
)
1714 uint32 attrib
= GetFileAttributesAndFileName(filename
, 0);
1716 if (attrib
& SCC_FILE_ATTRIBUTE_MANAGED
&& *m_ui
.m_depotFile
)
1718 cry_strcpy(outPath
, nOutPathSize
, m_ui
.m_depotFile
);
1724 bool CPerforceSourceControl::GetOtherUser(const char* filename
, char* outUser
, int nOutUserSize
)
1726 if (!filename
|| !outUser
)
1729 uint32 attrib
= GetFileAttributesAndFileName(filename
, 0);
1731 if (attrib
& SCC_FILE_ATTRIBUTE_MANAGED
&& *m_ui
.m_otherUser
)
1733 cry_strcpy(outUser
, nOutUserSize
, m_ui
.m_otherUser
);
1739 bool CPerforceSourceControl::History(const char* filename
)
1744 uint32 attrib
= GetFileAttributesAndFileName(filename
, 0);
1746 if (attrib
& SCC_FILE_ATTRIBUTE_MANAGED
&& *m_ui
.m_depotFile
)
1748 string commandLine
= string("-cmd \"history ") + string(m_ui
.m_depotFile
) + "\"";
1749 ShellExecute(NULL
, NULL
, "p4v.exe", commandLine
, NULL
, SW_SHOW
);
1755 bool CPerforceSourceControl::IsSomeTimePassed()
1757 const DWORD dwSomeTime
= 10000; // 10 sec
1758 static DWORD dwLastTime
= 0;
1759 DWORD dwCurTime
= GetTickCount();
1761 if (dwCurTime
- dwLastTime
> dwSomeTime
)
1763 dwLastTime
= dwCurTime
;
1770 bool CPerforceSourceControl::GetOtherLockOwner(const char* filename
, char* outUser
, int nOutUserSize
)
1772 if (NULL
== filename
|| NULL
== outUser
)
1775 uint32 attrib
= GetFileAttributesAndFileName(filename
, 0);
1776 if (attrib
& SCC_FILE_ATTRIBUTE_LOCKEDBYANOTHER
&& *m_ui
.m_lockedBy
)
1778 cry_strcpy(outUser
, nOutUserSize
, m_ui
.m_lockedBy
);
1785 ESccLockStatus
CPerforceSourceControl::GetLockStatus(const char* filename
)
1788 ESccLockStatus nRet
= SCC_LOCK_STATUS_UNLOCKED
;
1793 cry_strcpy(fl
, filename
);
1794 char* argv
[] = { fl
};
1796 m_client
.SetArgv(1, argv
);
1797 m_client
.Run("fstat", &m_ui
);
1800 if (!m_ui
.m_e
.Test())
1801 nRet
= SCC_LOCK_STATUS_UNLOCKED
; // default to not locked
1803 if (nRet
>= 0 // if no error
1804 && (0 == strcmp(m_ui
.m_action
, "edit") || 0 == strcmp(m_ui
.m_action
, "add")) // checked out
1807 nRet
= m_ui
.m_lockStatus
;
1814 bool CPerforceSourceControl::Lock(const char* filename
, int nFlags
)
1817 char fullFileName
[MAX_PATH
];
1818 uint32 attrib
= GetFileAttributesAndFileName(filename
, fullFileName
);
1820 if (!(attrib
& SCC_FILE_ATTRIBUTE_MANAGED
))
1823 if (!(attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
))
1825 if (false == CheckOut(filename
, 0))
1829 if (attrib
& SCC_FILE_ATTRIBUTE_LOCKEDBYANOTHER
)
1832 char* argv
[] = { fullFileName
};
1833 m_client
.SetArgv(1, argv
);
1834 m_client
.Run("lock", &m_ui
);
1835 return !m_ui
.m_e
.Test();
1838 bool CPerforceSourceControl::Unlock(const char* filename
, int nFlags
)
1841 char fullFileName
[MAX_PATH
];
1842 uint32 attrib
= GetFileAttributesAndFileName(filename
, fullFileName
);
1844 if (!(attrib
& SCC_FILE_ATTRIBUTE_MANAGED
))
1847 if (attrib
& SCC_FILE_ATTRIBUTE_LOCKEDBYANOTHER
)
1850 if (!(attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
))
1853 char* argv
[] = { fullFileName
};
1854 m_client
.SetArgv(1, argv
);
1855 m_client
.Run("unlock", &m_ui
);
1856 return !m_ui
.m_e
.Test();
1859 bool CPerforceSourceControl::GetUserName(char* outUser
, int nOutUserSize
)
1861 cry_strcpy(outUser
, nOutUserSize
, m_client
.GetUser().Text());
1865 bool CPerforceSourceControl::GetFileRev(const char* sFilename
, int64
* pHaveRev
, int64
* pHeadRev
)
1871 m_ui
.m_nFileHaveRev
= -1;
1872 m_ui
.m_nFileHeadRev
= -1;
1875 cry_strcpy(fl
, sFilename
);
1876 char* argv
[] = { fl
};
1877 m_client
.SetArgv(1, argv
);
1878 m_client
.Run("fstat", &m_ui
);
1881 if (m_ui
.m_nFileHaveRev
>= 0 || m_ui
.m_nFileHeadRev
>= 0)
1885 *pHaveRev
= m_ui
.m_nFileHaveRev
;
1887 *pHeadRev
= m_ui
.m_nFileHeadRev
;
1893 bool CPerforceSourceControl::GetRevision(const char* filename
, int64 nRev
, int nFlags
)
1896 char FullFileName
[MAX_PATH
];
1898 string files
= filename
;
1900 string file
= files
.Tokenize(";", curPos
);
1901 for (; !file
.IsEmpty(); file
= files
.Tokenize(";", curPos
))
1903 if (file
.Trim().IsEmpty())
1905 uint32 attrib
= GetFileAttributesAndFileName(file
, FullFileName
);
1907 cry_sprintf(&FullFileName
[strlen(FullFileName
)], sizeof(FullFileName
) - strlen(FullFileName
), "#%I64d", nRev
);
1909 if (!(attrib
& SCC_FILE_ATTRIBUTE_MANAGED
))
1912 if (attrib
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
&& (nFlags
& GETLATEST_REVERT
))
1914 char* argv
[] = { FullFileName
};
1915 m_client
.SetArgv(1, argv
);
1916 m_client
.Run("revert", &m_ui
);
1918 if (nFlags
& GETLATEST_ONLY_CHECK
)
1920 if (attrib
& SCC_FILE_ATTRIBUTE_FOLDER
)
1923 bRet
= IsFileLatestVersion(FullFileName
);
1927 char* argv
[] = { "-f", FullFileName
};
1928 m_client
.SetArgv(2, argv
);
1929 m_client
.Run("sync", &m_ui
);