mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1111 lines
29 KiB
1111 lines
29 KiB
//
|
|
// RSLM.C
|
|
//
|
|
// rslm - a huge multi-project tool
|
|
//
|
|
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <process.h>
|
|
#include <io.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <direct.h>
|
|
#include <windows.h>
|
|
|
|
/*
|
|
* Globals
|
|
*/
|
|
char szParentProject[32] = "";
|
|
char szParentServer[MAX_PATH] = "";
|
|
char szInfoFileName[MAX_PATH] = "rslm.ini";
|
|
char szDefInfoFileName[] = "rslm.ini";
|
|
char szSlmFileName[] = "slm.ini";
|
|
char szNoLock[] = "NoLock";
|
|
char szLocalMetaRoot[MAX_PATH] = "";
|
|
BOOL fAsync = FALSE;
|
|
BOOL fRecurse = FALSE;
|
|
BOOL fBuildFiles = FALSE;
|
|
BOOL fDebug = FALSE;
|
|
BOOL fBatch = FALSE;
|
|
BOOL fKeep = FALSE;
|
|
BOOL fMinimized = FALSE;
|
|
BOOL fValidate = FALSE;
|
|
int iOutputFile = 0;
|
|
WIN32_FIND_DATA wfd;
|
|
|
|
/*
|
|
* Prototypes
|
|
*/
|
|
BOOL SpawnEnlistCmd(char **argv, char *pszServer, char *pszProject);
|
|
BOOL SpawnSlmckCmd( char **argv, char *pszServer, char *pszProject);
|
|
BOOL SpawnOtherCmd( char **argv, char *pszServer, char *pszProject);
|
|
BOOL Noop( char **argv, char *pszServer, char *pszProject);
|
|
BOOL GrabReadLock( char **argv, char *pszServer, char *pszProject);
|
|
BOOL GrabWriteLock( char **argv, char *pszServer, char *pszProject);
|
|
BOOL ReleaseLock( char **argv, char *pszServer, char *pszProject);
|
|
BOOL CallRslm( char **argv, char *pszServer, char *pszProject);
|
|
|
|
/*
|
|
* structures
|
|
*/
|
|
typedef struct tagSPAWNINFO {
|
|
char *pszCmd;
|
|
BOOL (*pfnSpawn)(char **, char*, char*);
|
|
} SPAWNINFO, *PSPAWNINFO;
|
|
|
|
SPAWNINFO aLockCmdData[] = {
|
|
{ "ssync", GrabReadLock },
|
|
{ "in", GrabWriteLock },
|
|
{ NULL, Noop }
|
|
};
|
|
|
|
SPAWNINFO aPreCmdData[] = {
|
|
{ "enlist", SpawnEnlistCmd },
|
|
{ "slmck", SpawnSlmckCmd },
|
|
{ "defect", Noop },
|
|
{ "sadmin", SpawnSlmckCmd },
|
|
{ NULL, SpawnOtherCmd }
|
|
};
|
|
|
|
SPAWNINFO aPostCmdData[] = {
|
|
{ "defect", SpawnOtherCmd },
|
|
{ NULL, Noop }
|
|
};
|
|
|
|
SPAWNINFO aUnlockCmdData[] = {
|
|
{ "ssync", ReleaseLock },
|
|
{ "in", ReleaseLock },
|
|
{ NULL, Noop }
|
|
};
|
|
|
|
|
|
LPSTR *ParseCmdLine(
|
|
LPSTR *parg)
|
|
{
|
|
LPSTR arg;
|
|
|
|
++parg; // skip name of us
|
|
|
|
nextArg:
|
|
|
|
arg = *parg;
|
|
|
|
if (arg == NULL || (*arg != '-' && *arg != '/')) {
|
|
return(parg); // last arg
|
|
}
|
|
|
|
parg++; // parg points to next arg
|
|
|
|
while (TRUE) {
|
|
arg++; // skip switch char
|
|
switch (toupper(*arg)) {
|
|
case '\0':
|
|
case ' ':
|
|
goto nextArg;
|
|
|
|
case 'A':
|
|
fAsync = TRUE;
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -a\n");
|
|
}
|
|
break;
|
|
|
|
case 'B':
|
|
fBuildFiles = TRUE;
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -b\n");
|
|
}
|
|
break;
|
|
|
|
case 'C':
|
|
fBatch = TRUE;
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -c\n");
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
fDebug = TRUE;
|
|
fprintf(stderr, "PARAM: -d\n");
|
|
break;
|
|
|
|
case 'F':
|
|
if (*parg == NULL) {
|
|
goto usage;
|
|
}
|
|
strcpy(szInfoFileName, *parg++);
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -f %s\n", szInfoFileName);
|
|
}
|
|
goto nextArg;
|
|
|
|
case 'K':
|
|
fKeep = TRUE;
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -k\n");
|
|
}
|
|
break;
|
|
|
|
case 'L':
|
|
if (*parg == NULL) {
|
|
goto usage;
|
|
}
|
|
strcpy(szLocalMetaRoot, *parg++);
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -l %s\n", szLocalMetaRoot);
|
|
}
|
|
goto nextArg;
|
|
|
|
case 'M':
|
|
fMinimized = TRUE;
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -m\n");
|
|
}
|
|
break;
|
|
|
|
case 'P':
|
|
if (*parg == NULL) {
|
|
goto usage;
|
|
}
|
|
strcpy(szParentProject, *parg++);
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -p %s\n", szParentProject);
|
|
}
|
|
goto nextArg;
|
|
|
|
case 'R':
|
|
fRecurse = TRUE;
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -r\n");
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
if (*parg == NULL) {
|
|
goto usage;
|
|
}
|
|
strcpy(szParentServer, *parg++);
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -s %s\n", szParentServer);
|
|
}
|
|
goto nextArg;
|
|
|
|
case 'V':
|
|
fValidate = TRUE;
|
|
if (fDebug) {
|
|
fprintf(stderr, "PARAM: -v\n");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
usage:
|
|
fprintf(stderr, "usage: rslm [options] <command line>\n");
|
|
fprintf(stderr, " -a (async spawn)\n");
|
|
fprintf(stderr, " -b (build infofiles)\n");
|
|
fprintf(stderr, " -c (emit batch file to std out - no spawn)\n");
|
|
fprintf(stderr, " -d (debug mode)\n");
|
|
fprintf(stderr, " -f rslmfile (default=\"rslm.ini\")\n");
|
|
fprintf(stderr, " -k (keep async spawn windows around)\n");
|
|
fprintf(stderr, " -l lockdir (\"NoLock\" turns off meta locking)\n");
|
|
fprintf(stderr, " -m (async spawn windows minmimzed)\n");
|
|
fprintf(stderr, " -p project (defaults to slm.ini project)\n");
|
|
fprintf(stderr, " -r (do command on all dirs w/infofile.)\n");
|
|
fprintf(stderr, " -s slm_server (defaults to slm.ini server root)\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "set RSLM_OPTS environent variable for new defaults.\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "<command line> may contain the following substitute patterns:\n");
|
|
fprintf(stderr, " %%CUR_PATH%% => full path of Current Directory at spawn time.\n");
|
|
fprintf(stderr, " %%CUR_DIR%% => name of current directory at spawn time.\n");
|
|
_exit(1);
|
|
}
|
|
}
|
|
|
|
return(parg);
|
|
}
|
|
|
|
|
|
|
|
VOID mystrrpl(
|
|
char *psz,
|
|
char cFind,
|
|
char cReplace)
|
|
{
|
|
while (*psz != '\0') {
|
|
if (*psz == cFind) {
|
|
*psz = cReplace;
|
|
}
|
|
psz++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Open file named pszSlmFileName and fill pszProject and pszServer from
|
|
* that file. (buffers are assumed large enough) Returns fSuccess.
|
|
*/
|
|
BOOL ExtractSlmIniInfo(
|
|
char *pszSlmFileName,
|
|
char *pszProject,
|
|
char *pszServer)
|
|
{
|
|
static char szProjectKey[] = "project = ";
|
|
static char szServerKey[] = "slm root = ";
|
|
static char szSlmFileLine[MAX_PATH];
|
|
FILE *hFile;
|
|
char *psz, *psz2;
|
|
|
|
hFile = fopen(pszSlmFileName, "r");
|
|
if (hFile == NULL) {
|
|
return(FALSE);
|
|
}
|
|
fgets(szSlmFileLine, MAX_PATH, hFile); // line 1
|
|
|
|
psz = strstr(szSlmFileLine, szProjectKey);
|
|
if (psz == NULL) {
|
|
fclose(hFile);
|
|
return(FALSE);
|
|
}
|
|
strcpy(pszProject, psz + strlen(szProjectKey));
|
|
pszProject[strlen(pszProject) - 1] = '\0'; // remove \n
|
|
|
|
fgets(szSlmFileLine, MAX_PATH, hFile); // line 2
|
|
|
|
psz = strstr(szSlmFileLine, szServerKey);
|
|
if (psz == NULL) {
|
|
fclose(hFile);
|
|
return(FALSE);
|
|
}
|
|
psz += strlen(szServerKey);
|
|
if (psz[3] == ':') {
|
|
// Its a local slm project, clean up the string
|
|
psz += 2; // skip '//'
|
|
psz2 = strchr(psz, '/');
|
|
*--psz2 = ':';
|
|
*--psz2 = *psz;
|
|
psz = psz2;
|
|
}
|
|
strcpy(pszServer, psz);
|
|
pszServer[strlen(pszServer) - 1] = '\0'; // remove \n
|
|
mystrrpl(pszServer, '/', '\\');
|
|
|
|
fclose(hFile);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* Reads next line of hRslmFile and fills pszProject and pszServer with
|
|
* apropriate info from that line. Returns fSuccess.
|
|
*/
|
|
BOOL ExtractRslmLine(
|
|
FILE *hRslmFile,
|
|
LPSTR pszProject,
|
|
LPSTR pszServer)
|
|
{
|
|
char szBuf[100];
|
|
LPSTR psz;
|
|
|
|
if (fgets(szBuf, 100, hRslmFile) == NULL) {
|
|
return(FALSE);
|
|
}
|
|
psz = strchr(szBuf, ' ');
|
|
if (psz == NULL) {
|
|
return(FALSE);
|
|
}
|
|
*psz++ = '\0';
|
|
while (isspace(*psz)) {
|
|
psz++;
|
|
}
|
|
psz[strlen(psz) - 1] = '\0'; // remove \n
|
|
strcpy(pszServer, psz);
|
|
strcpy(pszProject, szBuf);
|
|
return(pszServer[0] && pszProject[0]);
|
|
}
|
|
|
|
|
|
/*
|
|
* Recurse from current directory depth first on all directories containing
|
|
* szSlmFileName files. Create szInfoFileName files at
|
|
* nodes where any descendant directories have projects differing from
|
|
* the parent directory's project.
|
|
*
|
|
* Returns fInfoFileCreated. Emits a message if directory structure is
|
|
* not ok. (ie, no rslm.ini file (except the root) should exist without
|
|
* its parent directory having an rslm.ini file too.
|
|
*/
|
|
BOOL BuildFiles(
|
|
LPSTR pszCurProj)
|
|
{
|
|
HANDLE hFF;
|
|
char szProject[32];
|
|
char szServer[MAX_PATH];
|
|
FILE *hInfoFile, *hFile;
|
|
char szCurPath[MAX_PATH];
|
|
BOOL fSlmOk;
|
|
BOOL fInfoFileCreated = FALSE;
|
|
BOOL fChildInfoFileCreated = FALSE;
|
|
|
|
GetCurrentDirectory(MAX_PATH, szCurPath);
|
|
|
|
//
|
|
// delete any existing rslm.ini file
|
|
//
|
|
hFile = fopen(szInfoFileName, "r");
|
|
if (hFile != NULL) {
|
|
fclose(hFile);
|
|
if (remove(szInfoFileName) == -1) {
|
|
fprintf(stderr, "RSLM: Could not delete %s\\%s\n", szCurPath,
|
|
szInfoFileName);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// for each subdirectory...
|
|
//
|
|
hFF = FindFirstFile("*.*", &wfd);
|
|
while (hFF) {
|
|
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
goto nextFile;
|
|
}
|
|
|
|
if (!strcmp(wfd.cFileName, "..") || !strcmp(wfd.cFileName, ".")) {
|
|
goto nextFile;
|
|
}
|
|
|
|
if (!SetCurrentDirectory(wfd.cFileName)) {
|
|
goto nextFile;
|
|
}
|
|
/*
|
|
* if this sub-directory doesn't have an slm.ini file, skip it.
|
|
*/
|
|
hFile = fopen(szSlmFileName, "r");
|
|
if (hFile == NULL) {
|
|
SetCurrentDirectory("..");
|
|
goto nextFile;
|
|
}
|
|
fclose(hFile);
|
|
|
|
fSlmOk = ExtractSlmIniInfo(szSlmFileName, szProject, szServer);
|
|
|
|
if (fSlmOk) {
|
|
fChildInfoFileCreated |= BuildFiles(szProject);
|
|
}
|
|
|
|
SetCurrentDirectory("..");
|
|
|
|
if (!fSlmOk) {
|
|
fprintf(stderr, "\nRSLM: Can't parse %s\\%s\\%s\n", szCurPath, wfd.cFileName, szSlmFileName);
|
|
} else {
|
|
/*
|
|
* Append child project info if its not part of the current proj.
|
|
*/
|
|
if (_stricmp(szProject, pszCurProj)) {
|
|
hInfoFile = fopen(szInfoFileName, "a");
|
|
if (hInfoFile == NULL) {
|
|
fprintf(stderr, "RSLM: Couldn't append to %s.\n", szInfoFileName);
|
|
return(FALSE);
|
|
}
|
|
fprintf(hInfoFile, "%s %s\n", szProject, szServer);
|
|
fclose(hInfoFile);
|
|
fprintf(stdout, "%s\\%s << %s %s\n", szCurPath, szInfoFileName, szProject, szServer);
|
|
fInfoFileCreated = TRUE;
|
|
}
|
|
}
|
|
|
|
nextFile:
|
|
if (!FindNextFile(hFF, &wfd)) {
|
|
FindClose(hFF);
|
|
break;
|
|
}
|
|
}
|
|
if (fDebug) {
|
|
fprintf(stderr, "RSLM: %d->%d at %s\n", fInfoFileCreated, fChildInfoFileCreated, szCurPath);
|
|
}
|
|
if (fChildInfoFileCreated && !fInfoFileCreated) {
|
|
fprintf(stderr, "RSLM: Invalid project structure at %s.\n", szCurPath);
|
|
}
|
|
return(fInfoFileCreated);
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine validates an RSLM metaproject by ssyncing all rslm.ini files
|
|
* and making sure the directory structure reflects what the rslm.ini file
|
|
* says it should be.
|
|
*
|
|
* 1) reconcile szInfoFileName file (if not rslm.ini) to new rslm.ini file.
|
|
* a) If the new rslm.ini file contains a project that is not in the
|
|
* szInfoFIleName file, add it to the szInfoFIleName File.
|
|
* b) If the new rslm.ini file server is different from the
|
|
* szInforFIleName file server name, fix the szInfoFileName server
|
|
* name. Add an entry to the global changed file.
|
|
* c) If the new rslm.ini file does not contain projects that are in
|
|
* the szInfoFileName file, comment out entry from the szInfoFileName
|
|
* file.
|
|
*
|
|
* 2) for each subdirectory that has an slm.ini file with a project
|
|
* different from the current project name:
|
|
* a) if it is NOT in the szInfoFIleName file, add entry to global
|
|
* remove project file.
|
|
*
|
|
* 3) recurse on all directories with an rslm.ini file.
|
|
*
|
|
* 4) for each non-comment entry in the szInfoFileName file:
|
|
* a) if no directory exists with the project name:
|
|
* 1) if project exists in removed global list, mv removed project
|
|
* to current directory and remove entry from global removed list.
|
|
* 2) otherwise, enlist in the new project.
|
|
*
|
|
* 5) for each project in the global removed list, defect from that node.
|
|
*
|
|
* 6) for each project in the global changed list, slmck that node.
|
|
*/
|
|
BOOL Validate(
|
|
LPSTR pszCurProj)
|
|
{
|
|
#if 0
|
|
char szCurDir[MAX_PATH];
|
|
FILE *hInfoFile;
|
|
|
|
static char *ssyncArgs[] = { "ssync", "rslm.ini", NULL };
|
|
|
|
if (fBatch) {
|
|
fprintf(stderr, "RSLM: Can't validate in batch mode.\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (fAsync) {
|
|
fprintf(stderr, "RSLM: Can't validate in assync mode.\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (fRecurse) {
|
|
fprintf(stderr, "RSLM: Can't validate in recurse mode.\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
GetCurrentDirectory(MAX_PATH, szCurDir);
|
|
|
|
MySpawn(P_WAIT, ssyncArgs, NULL, 0);
|
|
if (_stricmp(szInfoFileName, szDefInfoFileName)) {
|
|
ReconcileInfoFile();
|
|
}
|
|
|
|
hInfoFile = fopen(szInfoFileName, "r");
|
|
if (hInfoFile == NULL) {
|
|
hInfoFile = fopen(szDefInfoFileName, "r");
|
|
if (hInfoFile == NULL) {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// for each subdirectory...
|
|
//
|
|
hFF = FindFirstFile("*.*", &wfd);
|
|
while (hFF) {
|
|
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
goto nextFile;
|
|
}
|
|
|
|
if (!strcmp(wfd.cFileName, "..") || !strcmp(wfd.cFileName, ".")) {
|
|
goto nextFile;
|
|
}
|
|
|
|
if (!SetCurrentDirectory(wfd.cFileName)) {
|
|
goto nextFile;
|
|
}
|
|
/*
|
|
* if this sub-directory doesn't have an slm.ini file, skip it.
|
|
*/
|
|
hFile = fopen(szSlmFileName, "r");
|
|
if (hFile == NULL) {
|
|
SetCurrentDirectory("..");
|
|
goto nextFile;
|
|
}
|
|
fclose(hFile);
|
|
|
|
fSlmOk = ExtractSlmIniInfo(szSlmFileName, szDirProject, szDirServer);
|
|
|
|
SetCurrentDirectory("..");
|
|
|
|
if (!fSlmOk) {
|
|
goto nextFile;
|
|
}
|
|
|
|
/*
|
|
* searsh rslm.ini file for szThisProject
|
|
*/
|
|
rewind(hInfoFile);
|
|
while (ExtractRslmLine(hInfoFile, szThisProject, szThisServer)) {
|
|
if (!_stricmp(szThisProject, szDirProject) {
|
|
if (_stricmp(szThisServer, szDirServer)) {
|
|
goto nextFile; // cool, no problems
|
|
} else {
|
|
Append(pszChanged, szThisProject, szThisServer, szCurDir);
|
|
goto nextFile;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Getting here means we did not find an rslm.ini line to account
|
|
* for szThisProject. We need to remove it.
|
|
*/
|
|
Append(pszRemoved, szThisProject, szThisServer, szCurDir);
|
|
|
|
nextFile:
|
|
if (!FindNextFile(hFF, &wfd)) {
|
|
FindClose(hFF);
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(hInfoFile);
|
|
#endif
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
char *Substitute(
|
|
char *pszIn)
|
|
{
|
|
static char szCurDir[MAX_PATH];
|
|
char *pszOut, *pszOut2;
|
|
|
|
if (!_stricmp(pszIn, "%%CUR_PATH%%") ||
|
|
!strcmp(pszIn, "%%CUR_DIR%%")) {
|
|
GetCurrentDirectory(MAX_PATH, szCurDir);
|
|
pszOut = szCurDir;
|
|
if (!_stricmp(pszIn, "%%CUR_DIR%%")) {
|
|
pszOut = strrchr(szCurDir, '\\');
|
|
if (pszOut == NULL) {
|
|
pszOut = szCurDir;
|
|
} else {
|
|
pszOut++;
|
|
}
|
|
}
|
|
return(pszOut);
|
|
}
|
|
return(pszIn);
|
|
}
|
|
|
|
/*
|
|
* spawns the command in argv using the mode form. If argInsert is provided,
|
|
* those params are inserted into the argv params at param offset
|
|
* cCommandsBeforeInsert. If fRelease is set, the -r switch is propigated
|
|
* on spawns if "rslm" is an arguement.
|
|
*
|
|
* stdout is flushed after each spawn.
|
|
*/
|
|
int MySpawn(
|
|
int mode,
|
|
char *argv[],
|
|
char *argInsert[],
|
|
int cCommandsBeforeInsert)
|
|
{
|
|
char *modarg[32];
|
|
int iMod, iRet, j, k, iArg, iAdded;
|
|
char szFullPath[MAX_PATH];
|
|
char szCurDir[MAX_PATH];
|
|
char *pszFilePart;
|
|
DWORD dw;
|
|
|
|
iMod = 0;
|
|
iArg = 0;
|
|
iAdded = 0;
|
|
if (fAsync) {
|
|
modarg[iMod++] = "start";
|
|
iAdded++;
|
|
if (fMinimized) {
|
|
modarg[iMod++] = "/MIN";
|
|
iAdded++;
|
|
}
|
|
if (fKeep) {
|
|
modarg[iMod++] = "cmd";
|
|
iAdded++;
|
|
modarg[iMod++] = "/K";
|
|
iAdded++;
|
|
}
|
|
}
|
|
while (iMod < cCommandsBeforeInsert + iAdded && argv[iArg] != NULL) {
|
|
modarg[iMod++] = Substitute(argv[iArg++]);
|
|
}
|
|
j = iMod;
|
|
while (argInsert != NULL && argInsert[iMod - j] != NULL) {
|
|
modarg[iMod] = Substitute(argInsert[iMod - j]);
|
|
iMod++;
|
|
}
|
|
while (argv[iArg] != NULL) {
|
|
modarg[iMod++] = Substitute(argv[iArg++]);
|
|
}
|
|
modarg[iMod] = NULL;
|
|
|
|
searchIt:
|
|
|
|
if (!SearchPath(NULL, modarg[0], ".com", MAX_PATH, szFullPath, &pszFilePart))
|
|
if (!SearchPath(NULL, modarg[0], ".exe", MAX_PATH, szFullPath, &pszFilePart))
|
|
if (!SearchPath(NULL, modarg[0], ".cmd", MAX_PATH, szFullPath, &pszFilePart))
|
|
if (!SearchPath(NULL, modarg[0], ".bat", MAX_PATH, szFullPath, &pszFilePart)) {
|
|
/*
|
|
* assume its an internal command
|
|
*/
|
|
for (iMod = 30; iMod; iMod--) {
|
|
modarg[iMod] = modarg[iMod - 2];
|
|
}
|
|
modarg[0] = "cmd";
|
|
modarg[1] = "/c";
|
|
goto searchIt;
|
|
}
|
|
|
|
if (fDebug) {
|
|
fprintf(stderr, "RSLM: spawning: ");
|
|
for (iMod = 0; modarg[iMod] != NULL; iMod++) {
|
|
fprintf(stderr, "%s ", modarg[iMod]);
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
if (fBatch) {
|
|
GetCurrentDirectory(MAX_PATH, szCurDir);
|
|
fprintf(stdout, "cd %s\n", szCurDir);
|
|
for (iMod = 0; modarg[iMod] != NULL; iMod++) {
|
|
fprintf(stdout, "%s ", modarg[iMod]);
|
|
}
|
|
fprintf(stdout, "\n");
|
|
iRet = 0;
|
|
} else {
|
|
modarg[0] = szFullPath;
|
|
iRet = spawnv(mode, modarg[0], modarg);
|
|
}
|
|
fflush(stdout);
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
|
|
BOOL GrabReadLock(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject)
|
|
{
|
|
static char *readlockargs[] = {
|
|
"cookie", "-r", "-c", "\"Autolock - (RSLM)\"", NULL
|
|
};
|
|
char szCurDir[MAX_PATH];
|
|
int iRet;
|
|
|
|
if (!_stricmp(szLocalMetaRoot, szNoLock)) {
|
|
return(TRUE); // skip locks
|
|
}
|
|
|
|
/*
|
|
* cd to local dir with meta-project locks
|
|
*/
|
|
GetCurrentDirectory(MAX_PATH, szCurDir);
|
|
if (!SetCurrentDirectory(szLocalMetaRoot)) {
|
|
fprintf(stderr, "RSLM: Bad or unspecified rslm lock directory [%s].\n",
|
|
szLocalMetaRoot);
|
|
return(FALSE);
|
|
}
|
|
/*
|
|
* Get the cookie!
|
|
*/
|
|
iRet = MySpawn(P_WAIT, readlockargs, NULL, 0);
|
|
if (fBatch) {
|
|
fprintf(stdout, "if ERRORLEVEL==1 goto end\n");
|
|
}
|
|
SetCurrentDirectory(szCurDir);
|
|
if (iRet) {
|
|
fprintf(stderr, "RSLM: Unable to obtain root lock.\n");
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL GrabWriteLock(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject)
|
|
{
|
|
static char *readlockargs[] = {
|
|
"cookie", "-w", "-c", "\"Autolock - (RSLM)\"", NULL
|
|
};
|
|
char szCurDir[MAX_PATH];
|
|
int iRet;
|
|
|
|
if (!_stricmp(szLocalMetaRoot, szNoLock)) {
|
|
return(TRUE); // skip locks
|
|
}
|
|
|
|
/*
|
|
* cd to local dir with meta-project locks
|
|
*/
|
|
GetCurrentDirectory(MAX_PATH, szCurDir);
|
|
if (!SetCurrentDirectory(szLocalMetaRoot)) {
|
|
fprintf(stderr, "RSLM: Bad or unspecified rslm lock directory [%s].\n",
|
|
szLocalMetaRoot);
|
|
return(FALSE);
|
|
}
|
|
/*
|
|
* Get the cookie!
|
|
*/
|
|
iRet = MySpawn(P_WAIT, readlockargs, NULL, 0);
|
|
SetCurrentDirectory(szCurDir);
|
|
if (iRet) {
|
|
fprintf(stderr, "RSLM: Unable to obtain root lock.\n");
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL ReleaseLock(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject)
|
|
{
|
|
static char *freelockargs[] = {
|
|
"cookie", "-f", NULL
|
|
};
|
|
char szCurDir[MAX_PATH];
|
|
int iRet;
|
|
|
|
if (!_stricmp(szLocalMetaRoot, szNoLock)) {
|
|
return(TRUE); // skip locks
|
|
}
|
|
|
|
/*
|
|
* cd to local dir with meta-project locks
|
|
*/
|
|
GetCurrentDirectory(MAX_PATH, szCurDir);
|
|
if (!SetCurrentDirectory(szLocalMetaRoot)) {
|
|
fprintf(stderr, "RSLM: Bad or unspecified rslm lock directory.\n");
|
|
fprintf(stderr, "RSLM: Use -l parameter or set RSLM_LOCK_DIR variable.\n");
|
|
return(FALSE);
|
|
}
|
|
/*
|
|
* Release the cookie!
|
|
*/
|
|
iRet = MySpawn(P_WAIT, freelockargs, NULL, 0);
|
|
if (fBatch) {
|
|
fprintf(stdout, ":end\n");
|
|
}
|
|
SetCurrentDirectory(szCurDir);
|
|
if (iRet) {
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL SpawnEnlistCmd(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject)
|
|
{
|
|
int i;
|
|
static char*ssyncargs[] = {
|
|
"ssync", "-u", "rslm.ini", NULL
|
|
};
|
|
char *parentArgs[] = { "-s", pszParentServer, "-p", pszParentProject, NULL };
|
|
|
|
/*
|
|
* enlist requires p and s flags to be specified
|
|
*/
|
|
if (!*pszParentProject || !*pszParentServer) {
|
|
fprintf(stderr, "RSLM: -p and/or -s parameter to rslm is missing.\n");
|
|
return(FALSE);
|
|
}
|
|
/*
|
|
* find out where to insert -p and -s parameters
|
|
*/
|
|
for (i = 1; argv[i] != NULL && (*argv[i] == '-' || *argv[i] == '/'); i++) {
|
|
}
|
|
/*
|
|
* run enlist cmd
|
|
*/
|
|
if (MySpawn(P_WAIT, argv, parentArgs, i)) {
|
|
return(FALSE);
|
|
}
|
|
/*
|
|
* ssync to rslm.ini file so we can continue recursing
|
|
*/
|
|
if (MySpawn(P_WAIT, ssyncargs, NULL, 0)) {
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
BOOL SpawnSlmckCmd(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject)
|
|
{
|
|
int i;
|
|
char *parentArgs[] = { "-s", pszParentServer, "-p", pszParentProject, NULL };
|
|
|
|
/*
|
|
* slmck requires p and s flags to be specified
|
|
*/
|
|
if (!*pszParentProject || !*pszParentServer) {
|
|
fprintf(stderr, "RSLM: -p and/or -s parameter to rslm is missing.\n");
|
|
return(FALSE);
|
|
}
|
|
/*
|
|
* find out where to insert -p and -s parameters
|
|
*/
|
|
for (i = 1; argv[i] != NULL && (*argv[i] == '-' || *argv[i] == '/'); i++) {
|
|
}
|
|
/*
|
|
* run slmck-like cmd
|
|
*/
|
|
if (MySpawn(P_WAIT, argv, parentArgs, i)) {
|
|
return(FALSE);
|
|
}
|
|
/*
|
|
* correct project and server names if they are wrong or not supplied.
|
|
*/
|
|
return(ExtractSlmIniInfo(szSlmFileName, pszParentProject, pszParentServer));
|
|
}
|
|
|
|
|
|
|
|
BOOL SpawnOtherCmd(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject)
|
|
{
|
|
pszParentServer;
|
|
pszParentProject;
|
|
|
|
return(!MySpawn(P_WAIT, argv, NULL, 0));
|
|
}
|
|
|
|
|
|
BOOL Noop(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject)
|
|
{
|
|
argv;
|
|
pszParentServer;
|
|
pszParentProject;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL SpawnCommand(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject,
|
|
PSPAWNINFO psi)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; TRUE; i++) {
|
|
if (psi[i].pszCmd == NULL ||
|
|
!_stricmp(argv[0], psi[i].pszCmd)) {
|
|
return(psi[i].pfnSpawn(argv, pszParentServer, pszParentProject));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CallRslm(
|
|
char **argv,
|
|
char *pszParentServer,
|
|
char *pszParentProject)
|
|
{
|
|
static int cIndent = 0;
|
|
int i;
|
|
HANDLE hFF;
|
|
FILE *hOutputFile, *hInfoFile;
|
|
char szSpawnProject[32];
|
|
char szSpawnServer[MAX_PATH];
|
|
|
|
if (fDebug) {
|
|
for (i = 0; i < cIndent; i++) {
|
|
fprintf(stderr, " ");
|
|
}
|
|
fprintf(stderr, "\\\n");
|
|
for (i = 0; i < cIndent; i++) {
|
|
fprintf(stderr, " ");
|
|
}
|
|
fprintf(stderr, " \\\n");
|
|
cIndent++;
|
|
}
|
|
|
|
SpawnCommand(argv, pszParentServer, pszParentProject, aPreCmdData);
|
|
|
|
/*
|
|
* Now spawn child projects as specified by the rslm.ini file.
|
|
*
|
|
* Spawn propigates proper -p and -s parameters to rslm.
|
|
*/
|
|
hInfoFile = fopen(szInfoFileName, "r");
|
|
if (hInfoFile == NULL) {
|
|
/*
|
|
* szInfoFileName may be a custom file name, try for the default name
|
|
*/
|
|
hInfoFile = fopen(szDefInfoFileName, "r");
|
|
}
|
|
if (hInfoFile != NULL) {
|
|
while (ExtractRslmLine(hInfoFile, szSpawnProject, szSpawnServer)) {
|
|
if (!SetCurrentDirectory(szSpawnProject)) {
|
|
fprintf(stderr, "RSLM: Creating %s directory\n", szSpawnProject);
|
|
_mkdir(szSpawnProject);
|
|
if (!SetCurrentDirectory(szSpawnProject)) {
|
|
fprintf(stderr, "RSLM: Could not create %s directory\n", szSpawnProject);
|
|
goto leave;
|
|
}
|
|
}
|
|
|
|
CallRslm(argv, szSpawnServer, szSpawnProject);
|
|
|
|
SetCurrentDirectory("..");
|
|
}
|
|
fclose(hInfoFile);
|
|
}
|
|
|
|
SpawnCommand(argv, pszParentServer, pszParentProject, aPostCmdData);
|
|
|
|
/*
|
|
* Now, if fRecurse is indicated, spawn all child directories w/o an
|
|
* rslm.ini file. This spawn propigates -p and -s parameters to rslm.
|
|
*/
|
|
if (fRecurse) {
|
|
hFF = FindFirstFile("*.*", &wfd);
|
|
while (hFF) {
|
|
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
goto nextFile;
|
|
}
|
|
|
|
if (!strcmp(wfd.cFileName, "..") || !strcmp(wfd.cFileName, ".")) {
|
|
goto nextFile;
|
|
}
|
|
|
|
if (!SetCurrentDirectory(wfd.cFileName)) {
|
|
goto nextFile;
|
|
}
|
|
if (!ExtractSlmIniInfo(szSlmFileName, szSpawnProject, szSpawnServer)) {
|
|
goto nextFile2;
|
|
}
|
|
/*
|
|
* If the project key in the slmini file != the parent project,
|
|
* skip this directory.
|
|
*/
|
|
if (_stricmp(szSpawnProject, pszParentProject)) {
|
|
if (fDebug) {
|
|
fprintf(stderr, "RSLM: %s != %s\n", szSpawnProject, pszParentProject);
|
|
}
|
|
goto nextFile2;
|
|
}
|
|
|
|
CallRslm(argv, szSpawnServer, szSpawnProject);
|
|
|
|
nextFile2:
|
|
SetCurrentDirectory("..");
|
|
|
|
nextFile:
|
|
if (!FindNextFile(hFF, &wfd)) {
|
|
FindClose(hFF);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
leave:
|
|
|
|
if (fDebug) {
|
|
cIndent--;
|
|
for (i = 0; i < cIndent; i++) {
|
|
fprintf(stderr, " ");
|
|
}
|
|
fprintf(stderr, " /\n");
|
|
for (i = 0; i < cIndent; i++) {
|
|
fprintf(stderr, " ");
|
|
}
|
|
fprintf(stderr, "/\n");
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
main (argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int defargc;
|
|
char *buf[25];
|
|
char **defargv = buf;
|
|
LPSTR psz;
|
|
char szDefParams[MAX_PATH] = "";
|
|
char szDefParamsEnv[] = "RSLM_OPTS";
|
|
|
|
/*
|
|
* First get default args from environment and parse them.
|
|
*/
|
|
GetEnvironmentVariable(szDefParamsEnv, szDefParams, MAX_PATH);
|
|
|
|
psz = szDefParams;
|
|
defargv[0] = "";
|
|
defargc = 1;
|
|
while (*psz != '\0') {
|
|
while (*psz == ' ') { // scan to next token
|
|
*psz++;
|
|
}
|
|
if (*psz == '\0') { // quit if at NULL
|
|
break;
|
|
}
|
|
defargv[defargc++] = psz++; // mark start of token
|
|
while (*psz != ' ' && *psz != '\0') { // scan over token
|
|
*psz++;
|
|
}
|
|
if (*psz == ' ') { // terminate token
|
|
*psz++ = '\0';
|
|
}
|
|
}
|
|
defargv[defargc] = NULL;
|
|
ParseCmdLine(defargv);
|
|
|
|
/*
|
|
* Now parse the main command line.
|
|
*/
|
|
argv = ParseCmdLine(argv);
|
|
|
|
if (fBuildFiles) {
|
|
char szCurProj[MAX_PATH];
|
|
|
|
GetCurrentDirectory(sizeof(szCurProj), szCurProj);
|
|
BuildFiles(strrchr(szCurProj, '\\') + 1);
|
|
fprintf(stderr, "RSLM: %s files are built.\n", szInfoFileName);
|
|
}
|
|
|
|
if (fValidate) {
|
|
char szCurProj[MAX_PATH];
|
|
|
|
GetCurrentDirectory(sizeof(szCurProj), szCurProj);
|
|
Validate(strrchr(szCurProj, '\\') + 1);
|
|
fprintf(stderr, "RSLM: metaproject is validated.\n", szInfoFileName);
|
|
}
|
|
|
|
if (*argv) {
|
|
if (!SpawnCommand(argv, szParentServer, szParentProject, aLockCmdData)) {
|
|
return(0);
|
|
}
|
|
|
|
CallRslm(argv, szParentServer, szParentProject);
|
|
|
|
SpawnCommand(argv, szParentServer, szParentProject, aUnlockCmdData);
|
|
}
|
|
|
|
return(0);
|
|
}
|