Friday, August 31, 2018

Git local repository concept is really a confusion

Now only I got to know that there are 2 "types" of the local repository in the Git world. The first one is used to compare it against the local repository, where the command for this is git diff ; the second one is used to compare it against the remote repository, where the command for this is git diff --cached. One thing that really confuses me is there are 2 stages in local repository, one is called Changes not staged or commit, whereas the other one is called Changes to be committed

Confuse huh? Every time when I have done something, and I need to know the changes happen to my local PC, I'll use the command git status. The following will shows up:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

 modified:   backupUtilUnitTest/backupUtilUnitTest.pro
 modified:   core/BackupHeader.h
 modified:   core/FileBot.cpp
 modified:   core/FileBot.h
 modified:   core/FileHelper.cpp
 modified:   core/FileHelper.h
 modified:   core/FileNode.h
 new file:   unittest/FileBotUnderTest.cpp
 new file:   unittest/FileBotUnderTest.h
 modified:   unittest/testloadfiles.cpp
 new file:   unittest/testsearch.cpp

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

 modified:   backupUtilUnitTest/backupUtilUnitTest.pro.user
 modified:   unittest/testlab.cpp

Untracked files:
  (use "git add <file>..." to include in what will be committed)

 backupUtil.zip
 backupUtilUnitTest/backupUtilUnitTest.pro.user.RX2720

Take closer attention here, when I have changes to my work in my local computer, only git diff is useful here. If I use the command git diff --cached will show nothing. This experiment shows that I am comparing the changes with the work locate in the local PC with the local repository locate at the level named Changes not staged for commit. When I issue the command git add , the file will be moved from the level of Changes not staged for commit to a new level named Changes to be committed. Nothing will show up if the command git diff is used. At this stage, git diff --cached can only be used, and this will only compare the file at the level named Changes to be committed to the remote repository, not the one in local PC. If anything has been changed to the file, the changes will not reflect with this command. But if I use the command git diff , this will show on the changes I have made to the file in local PC.

Monday, August 27, 2018

constructChildPath() need to be clean

Currently the constructChildPath() is taking 2 arguments, the first argument is a pointer to a FileNode type and the second argument is a string.
void FileBot::constructChildPath(FileNode *currentPath, string inputPath)
{
   ...
   ...
}
The purpose of having these 2 arguments is to allow the method to identify where should I scan the path and where should I start parking those paths in the list. I have been thinking for so long to revamp this method so that it doesn't take any argument for its process. I'm just trying to make it as clean as possible.

Here is my thought on the finding. In this method, the string argument, is the crucial part of this method because it tells me where should I start scanning the path. If it doesn't contain any value, then nothing would be scanned, the return list would be empty. A screenshot of the piece is as follows:
void FileBot::constructChildPath(FileNode *currentPath, string inputPath)
{
    vector<path> pathList;

    // do not proceed for root path
    if( inputPath == "" )
        return;

    // capture the paths/files list under the source
    copy(filesystem::directory_iterator(inputPath), filesystem::directory_iterator(), back_inserter(pathList));

    std::sort(pathList.begin(), pathList.end());

    // scan through path and those files sit in that path
    // scan for files in sub directory if there is any sub directory in that path
    for(vector<path>::const_iterator it(pathList.begin()); it != pathList.end(); ++it) {
        string file = FileHelper::convertPathToString((*it));

        if( is_directory(file) ) {
            FileNode *node = new FileNode();
            node->setName(file.substr(file.find_last_of(boost::filesystem::path::preferred_separator) + 1, file.length()));
            node->setType('d');
            node->setParentNode(currentPath);

            currentPath->sibling.push_back(*node);

            BOOST_LOG_TRIVIAL(info) << "subFolderName : " << node->getName().string() << " : " << node;

            constructChildPath(node, inputPath + string(1, boost::filesystem::path::preferred_separator) + node->getName().string());
        }

    ...
    ...
}
As mention in the code above, this is a recursive function, it will recursively dive into itself searching for more files when it sees a directory. Hence, the second argument of this method, inputPath, is constantly extending the directory underneath the current path. This method is only accessible through following method and it is highly dependent on the constructParentPath() because it needs a very important element for child path construction:
FileNode* FileBot::loadLocalFS(boost::filesystem::path inputPath)
{
    if( valiateRootPath(inputPath.generic_string()) == false ) {
        BOOST_LOG_TRIVIAL(info) << "Failed to validate input path";
        return nullptr;
    }

    constructParentPath(inputPath);
    constructChildPath(searchPath, inputPath.string());

    return searchPath;
}
Notice there is a junk variable called searchPath. I called it junk because it serves for temporary purpose. This variable was used to store the home path, which was generated in constructParentPath() as mention above, and then this variable will pass down to the constructChildPath(). This is what I mention the code is highly depends on others. Duhhh~

I'm restudy the code to see what I could improve about these junk code. As I first start, I remove the inputPath argument because I felt it was a redundant. It can generate on the spot from the currentPath, below is the upgrade version of this change:
void FileBot::constructChildPath(FileNode *currentPath)
{
    vector<path> pathList;

    // for the first time, retrieve the root path
    // bail otherwise
    if( currentPath == nullptr ) {
        return;
    }

    // construct path address
    string inputPath = constructPathAddress(currentPath);

    // capture the paths/files list under the source
    copy(filesystem::directory_iterator(inputPath), filesystem::directory_iterator(), back_inserter(pathList));

    std::sort(pathList.begin(), pathList.end());

    // scan through path and those files sit in that path
    // scan for files in sub directory if there is any sub directory in that path
    for(vector<path>::const_iterator it(pathList.begin()); it != pathList.end(); ++it) {
        string file = FileHelper::convertPathToString((*it));

        if( is_directory(file) ) {
            FileNode *node = new FileNode();
            node->setName(file.substr(file.find_last_of(boost::filesystem::path::preferred_separator) + 1, file.length()));
            node->setType('d');
            node->setParentNode(currentPath);

            currentPath->sibling.push_back(*node);

            BOOST_LOG_TRIVIAL(info) << "subFolderName : " << node->getName().string() << " : " << node;

            constructChildPath(node);
        }

    ...
    ...
}
Since the string argument has been removed, the caller doesn't require to pass down the inputPath anymore and also the searchPath is no longer there. The caller has been trimmed down as below:
FileNode* FileBot::loadLocalFS(boost::filesystem::path inputPath)
{
    constructChildPath(constructParentPath(inputPath));

    return localHome;
}
Since searchPath has already taken away, this will have a major impact on constructParentPath() as well, thus I have the following logic append to the end of the method:
FileNode* FileBot::constructParentPath(boost::filesystem::path inputPath, FileListType listType)
{
    ...

    if( listType == local ) {
        localHome = parent;
        return localHome;
    }
    else {
        remoteHome = parent;
        return remoteHome;
    }

//    return searchPath;
}