Skip to content
Permalink
Browse files

WIP on reading user name from Git settings (we probably won't need th…

…is, but we can always roll it back).
  • Loading branch information...
uliwitness committed Dec 5, 2018
1 parent 7a29895 commit 18881accb5eaf5275b14894db29f35b29004ae8c
Showing with 133 additions and 21 deletions.
  1. +3 −0 README.md
  2. +71 −10 bugmatic/bugmatic.cpp
  3. +5 −2 bugmatic/bugmatic.hpp
  4. +47 −5 bugmatic/configfile.cpp
  5. +7 −4 bugmatic/configfile.hpp
@@ -7,6 +7,9 @@ The idea is that just as you can download your Git repository from Github
and fully use it while you are on a plane, you should be able to manage your
Github Issues.

Another goal of Bugmatic is to provide a way to back up Github issues
in an open file format.

## Usage example:

mac:~ user$ mkdir mybugs
@@ -377,6 +377,21 @@ std::string remote::url() const
}


void working_copy::load_user_info()
{
if( mWorkingCopyPath.length() > 0 )
{
const char *homeDir = getenv("HOME");
if( homeDir )
{
configfile gitSettings( filesystem::path(homeDir) / filesystem::path(".gitconfig"), '=' );
mUserName = gitSettings["name"];
mUserEmail = gitSettings["email"];
}
}
}


void working_copy::init()
{
chdir( mWorkingCopyPath.c_str() );
@@ -707,16 +722,56 @@ void working_copy::push( const remote& inRemote )

list( std::vector<std::string>(), [inRemote,&hashesFile,this]( issue_info currIssue )
{
string url( inRemote.url() );
url.append("/issues");

Json postBodyJson = currIssue.issue_json();
string postBody = postBodyJson.dump();
string postHashStr = hash_string(postBody);
string hashesFileEntry = hashesFile.value_for_key(to_string(currIssue.issue_number()));
int bugNumber = currIssue.issue_number();
string url = currIssue.url();

if( currIssue.url() == "" ) // New, not yet on Github.
if( url == "" ) // New, not yet on server?
{
url = inRemote.url();
url.append("/issues");
}
else if( postHashStr != hashesFileEntry ) // Already on server, but changed locally.
{
string errMsg;
string remoteJsonData = raw_download( url, inRemote.user_name(), inRemote.password() );
Json remoteJson = Json::parse( remoteJsonData, errMsg );
if( errMsg.length() == 0 )
{
if( remoteJson["message"].is_string() )
{
stringstream ss;
ss << "GET request to " << url << " failed with Github error: " << remoteJson["message"].string_value();
throw runtime_error( ss.str() );
}
}
else
{
stringstream ss;
ss << "GET request to " << url << " failed with Json parsing error: " << errMsg;
throw runtime_error( ss.str() );
}

filter_issue_body_from_github(remoteJson);

string remoteJsonDataUnpacked = remoteJson.dump();
string remoteHash = hash_string(remoteJsonDataUnpacked);

if( remoteHash != hashesFileEntry )
{
stringstream ss;
ss << "Issue #" << currIssue.issue_number() << " has been changed locally and remotely. Can't yet merge issues.";
cout << "===== local: =====" << endl << postBody << endl << "===== remote: =====" << endl << remoteJsonData << endl << "===== remote reformatted: =====" << endl << remoteJsonDataUnpacked;
throw runtime_error( ss.str() );
}

// Only locally changed? We can push our changes upstream!
}

if( url != "" ) // Either creation or editing URL was set? Post new data!
{
url_request request;
url_reply reply;
@@ -791,12 +846,6 @@ void working_copy::push( const remote& inRemote )
throw runtime_error( ss.str() );
}
}
else if( postHashStr != hashesFileEntry ) // Changed locally.
{
stringstream ss;
ss << "Issue #" << currIssue.issue_number() << " has been changed locally. Can't yet push changes or merge issues.";
throw runtime_error( ss.str() );
}

for( comment_info& currComment : currIssue.comments() )
{
@@ -989,6 +1038,18 @@ void working_copy::filter_issue_body_from_github( Json &replyJson )
string uuid = issueBody.substr( uuidLabelEnd, uuidEnd - uuidLabelEnd );
replace_json_field("uuid", uuid, replyJson);
}

delete_json_field("comments", replyJson); // Don't consider number of attached comments changing a change on the issue itself.

// Now delete any fields that are `null`. Missing or `null` shouldn't make a difference to our hash.
map<string, Json> topLevelItems = replyJson.object_items();
for( auto keyValuePair : topLevelItems )
{
if( keyValuePair.second.is_null() )
{
delete_json_field(keyValuePair.first, replyJson);
}
}
}


@@ -158,9 +158,9 @@ class remote
class working_copy
{
public:
explicit working_copy( std::string inWorkingCopyPath = "" ) : mWorkingCopyPath(inWorkingCopyPath) {}
explicit working_copy( std::string inWorkingCopyPath = "" ) : mWorkingCopyPath(inWorkingCopyPath) { load_user_info(); }

void set_path( std::string inWorkingCopyPath ) { mWorkingCopyPath = inWorkingCopyPath; }
void set_path( std::string inWorkingCopyPath ) { mWorkingCopyPath = inWorkingCopyPath; load_user_info(); }
std::string path() { return mWorkingCopyPath; }

void init();
@@ -180,10 +180,13 @@ class working_copy
void filter_issue_body_from_github( json11::Json &replyJson );
void filter_issue_body_for_github( json11::Json &replyJson );

void load_user_info();
void push_comment( const remote& inRemote, issue_info& currIssue, comment_info& currComment );

std::string mWorkingCopyPath;
std::function<void(working_copy&)> mChangeHandler;
std::string mUserName;
std::string mUserEmail;
};

}
@@ -14,20 +14,32 @@ using namespace bugmatic;
using namespace std;


std::string bugmatic::configfile::value_for_key( const std::string& inKey )
const std::string bugmatic::configfile::operator []( const std::string& inKey ) const
{
return mKeys[inKey];
return value_for_key(inKey);
}


const std::string bugmatic::configfile::value_for_key( const std::string& inKey ) const
{
auto foundValue = mKeys.find(inKey);
if( foundValue == mKeys.end() )
{
return string();
}
return foundValue->second;
}


void bugmatic::configfile::set_value_for_key( const std::string& inKey, const std::string& inValue )
{
assert(inKey.find_first_of(string("\r\n") + mSeparator) == string::npos);

mKeys[inKey] = inValue;
mDirty = true;
}



bool bugmatic::configfile::save()
{
if( mDirty )
@@ -36,7 +48,7 @@ bool bugmatic::configfile::save()

for( auto currPair : mKeys )
{
settingsfile << currPair.first << ":" << currPair.second << "\n";
settingsfile << currPair.first << string(1, mSeparator) << currPair.second << "\n";
}
}

@@ -55,21 +67,51 @@ bool bugmatic::configfile::load()
int currCh = settingsfile.get();
if( currCh == EOF )
break;
if( inKey && currCh == ':' )
if( inKey && currCh == mSeparator )
inKey = false;
else if( inKey && currCh == '\n' )
{
if( key.find("[") == 0 && key.rfind("]") == key.length() -1 )
{
key = key.substr(1, key.length() -2) + ".";
}
else
{
key = "";
}
continue;
}
else if( !inKey && currCh == '\n' )
{
size_t actualStart = key.find_first_not_of("\t\r\n ");
if( actualStart == string::npos ) actualStart = 0;

size_t actualEnd = key.find_last_not_of("\t\r\n ");
if( actualEnd == string::npos ) actualEnd = key.length(); else ++actualEnd;

key = key.substr( actualStart, actualEnd - actualStart );

actualStart = value.find_first_not_of("\t\r\n ");
if( actualStart == string::npos ) actualStart = 0;

actualEnd = value.find_last_not_of("\t\r\n ");
if( actualEnd == string::npos ) actualEnd = key.length(); else ++actualEnd;

value = value.substr( actualStart, actualEnd - actualStart );

mKeys[key] = value;
key.erase();
value.erase();
inKey = true;
}
else if( inKey )
{
key.append(1, currCh);
}
else
{
value.append(1, currCh);
}
if( settingsfile.eof() )
break;
}
@@ -19,19 +19,22 @@ namespace bugmatic
class configfile
{
public:
configfile( const std::string& inPath ) : mPath(inPath) { load(); }
configfile( const std::string& inPath, char separator = ':' ) : mPath(inPath), mSeparator(separator) { load(); }
~configfile() { save(); }

std::string value_for_key( const std::string& inKey );
void set_value_for_key( const std::string& inKey, const std::string& inValue );
const std::string value_for_key( const std::string& inKey ) const;
void set_value_for_key( const std::string& inKey, const std::string& inValue );

bool save();
bool load();


const std::string operator []( const std::string& inKey ) const;

protected:
std::string mPath;
std::map<std::string,std::string> mKeys;
bool mDirty = false;
char mSeparator;
};

}

0 comments on commit 18881ac

Please sign in to comment.
You can’t perform that action at this time.