• C++ 小工具一键解决SVN Clean Up 失败的问题


     参考文章:

      1.http://blog.csdn.net/luochao_tj/article/details/46358145

      2.http://blog.csdn.net/segen_jaa/article/details/7938959

    可执行文件地址

      http://pan.baidu.com/s/1nvi7kW5

    使用方法:

      下载压缩包,解压出可执行文件 SvnCleanUp.exe (Debug 和 Release 均可),放到SVN目录下面,双击运行即可.

    完整VS工程地址:http://pan.baidu.com/s/1skECVDF 提取码 : lk5e

    原理:

      TortoiseSVN 把项目的cleanup信息和lock信息放在了.svn目录下的wd.db文件里面,这是一个sqlite数据库文件,如果手动CleanUp失败,我们只需要杀掉占用这个文件的SVN进程,然后把这个文件中的 WC_LOCK 和 WORK_QUEUE 表清空就好了.

    sqlite3源码文件官网地址:https://www.sqlite.org/2017/sqlite-amalgamation-3160100.zip 

    主要逻辑代码:

    #include <stdint.h>
    #include <stdio.h>
    #include <vector>
    #include <string>
    #include <io.h>
    #include <windows.h>
    #include <tlhelp32.h>
    #include "sqlite3/sqlite3.h"
    
    struct ProcessData
    {
        std::string name;
        int32_t id;
    };
    
    void ScanWCDBFiles(const std::string &startPath, std::vector<std::string> &files, const std::string &dbFileName);
    int32_t CleanOneDB(const std::string &dbFile);
    int32_t DeleteCallback(void *NotUsed, int argc, char **argv, char **azColName);
    
    void GetAllProcess(std::vector<ProcessData> &processes);
    bool KillProcessByID(int32_t pid);
    
    int32_t main(int32_t argc, char *argv[])
    {
        int32_t ret = 0;
        // kill all TSVN* processes
        const char *svnProcesses = "TSVN";
        std::vector<ProcessData> processes;
        GetAllProcess(processes);
        for (const ProcessData &p : processes)
        {
            ret = p.name.find(svnProcesses);
            if (ret >= 0)
            {
                printf("kill %s
    ", p.name.c_str());
                if (!KillProcessByID(p.id))
                {
                    printf("	failed!
    ");
                }
            }
        }
        int32_t succCount = 0, failCount = 0;
        std::vector<std::string> files;
        printf("scanning...
    ");
        ScanWCDBFiles(".", files, "wc.db");
        for (const std::string &file : files)
        {
            printf("cleaning [%s]
    ", file.c_str());
            ret = CleanOneDB(file);
            if (ret == S_OK)
            {
                ++succCount;
            }
            else
            {
                printf("clean [%s] failed!!!
    ", file.c_str());
                ++failCount;
            }
        }
        printf("clean finished.succ(s) %d, fail(s) %d.
    ", succCount, failCount);
        getchar();
        return 0;
    }
    
    void ScanWCDBFiles(const std::string &startPath, std::vector<std::string> &files, const std::string &dbFileName)
    {
        struct _finddata_t fileinfo;
        long hFile = 0;
        char tmpPath[MAX_PATH] = { 0 };
        sprintf_s(tmpPath, "%s\*", startPath.c_str());
        if ((hFile = _findfirst(tmpPath, &fileinfo)) == -1){ return; }
        do
        {
            if ((fileinfo.attrib &  _A_SUBDIR))
            {
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
                {
                    sprintf_s(tmpPath, "%s\%s", startPath.c_str(), fileinfo.name);
                    ScanWCDBFiles(tmpPath, files, dbFileName);
                }
            }
            else
            {
                if (dbFileName == fileinfo.name)
                {
                    sprintf_s(tmpPath, "%s\%s", startPath.c_str(), fileinfo.name);
                    files.push_back(tmpPath);
                }
            }
        } while (_findnext(hFile, &fileinfo) == 0);
        _findclose(hFile);
    }
    
    int32_t CleanOneDB(const std::string &dbFile)
    {
        const char* tables[] =
        {
            "WC_LOCK",
            "WORK_QUEUE",
            "LOCK"
        };
        sqlite3 * pDB = NULL;
        int32_t ret = sqlite3_open(dbFile.c_str(), &pDB);
        if (ret != SQLITE_OK)
        {
            printf("	open db %s failed.
    ", dbFile.c_str());
            return ret;
        }
        for (int32_t i = 0; i < sizeof(tables) / sizeof(tables[0]); ++i)
        {
            printf("	delete [%s]...
    ", tables[i]);
            char sql[256] = { 0 };
            sprintf_s(sql, "DELETE FROM %s;", tables[i]);
            char* errorMsg = NULL;
            ret = sqlite3_exec(pDB, sql, DeleteCallback, 0, &errorMsg);
            if (ret != SQLITE_OK)
            {
                printf("	select %s error![%s]
    ", tables[i], errorMsg);
                return ret;
            }
        }
        return 0;
    }
    
    int32_t DeleteCallback(void *NotUsed, int argc, char **argv, char **azColName)
    {
        return 0;
    }
    
    void GetAllProcess(std::vector<ProcessData> &processes)
    {
        HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (INVALID_HANDLE_VALUE == hSnapshot) {
            return;
        }
        PROCESSENTRY32 pe = { sizeof(pe) };
        for (BOOL ret = Process32First(hSnapshot, &pe); ret; ret = Process32Next(hSnapshot, &pe)) {
            ProcessData data;
            data.name = pe.szExeFile;
            data.id = pe.th32ProcessID;
            processes.push_back(data);
            //printf("%-6d %s
    ", pe.th32ProcessID, pe.szExeFile);
        }
        CloseHandle(hSnapshot);
    }
    
    bool KillProcessByID(int32_t pid)
    {
        HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
        if (hProcess == NULL) {
            return FALSE;
        }
        return TerminateProcess(hProcess, 0) != 0;
    }

    运行效果:

  • 相关阅读:
    并发与多线程
    java多线程--死锁
    java变量
    StringStringBufferStringBuilder区别
    java8新特性
    spring自动装配和通过java实现装配
    CSP -- 运营商内容劫持(广告)的终结者
    【Composer】实战操作二:自己创建composer包并提交
    【个人重点】开发中应该重视的几点
    【Composer】实战操作一:使用库
  • 原文地址:https://www.cnblogs.com/tangxin-blog/p/6253442.html
Copyright © 2020-2023  润新知