I have searched Google and Stackoverflow for an answer to the question of how to code the equivalent of
git commit -a -m "message"
in libgit2 (https://libgit2.github.com) and C or C++.
But I cannot find a ready and working answer to this question.
I am using libgit2-0.21.
Below is code that initializes a git repository, adds two files to it, and stages the two files so they are ready to be committed.
My question is how to code "git commit -a -m "msg" in libgit2?
#include <sys/stat.h>
#include <string>
#include <fstream>
#include <iostream>
#include <git2.h>
using namespace std;
int main (int argc, char** argv)
{
git_threads_init ();
// Create repository directory.
string directory = "repository";
mkdir (directory.c_str(), 0777);
// Initialize the repository: git init.
git_repository *repo = NULL;
int result = git_repository_init (&repo, directory.c_str(), false);
if (result != 0) cerr << giterr_last ()->message << endl;
// Store two files in the repository directory.
ofstream file;
file.open ("repository/file1", ios::binary | ios::trunc);
file << "Contents of file one";
file.close ();
file.open ("repository/file2", ios::binary | ios::trunc);
file << "Contents of file two";
file.close ();
// Run the equivalent of "git add ."
// Get the git index.
git_index * index = NULL;
result = git_repository_index (&index, repo);
if (result != 0) cerr << giterr_last ()->message << endl;
// Add all files to the git index.
result = git_index_add_all (index, NULL, 0, NULL, NULL);
if (result != 0) cerr << giterr_last ()->message << endl;
// Write the index to disk.
result = git_index_write (index);
if (result != 0) cerr << giterr_last ()->message << endl;
// Run the equivalent of "git commit -a -m "commit message".
// How to do that through libgit2?
// Run "git status" to see the result.
system ("cd repository; git status");
// Free resources.
git_index_free (index);
git_repository_free (repo);
git_threads_shutdown ();
return 0;
}
The code can be compiled as follows:
g++ -Wall -I/opt/local/include -L/opt/local/lib -lgit2 -o test git.cpp
Below is the output of running the compiled binary:
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1
new file: file2
Once the index is updated
create a tree from it through git_index_write_tree()
create a commit that references this tree through git_commit_create_v()
See this end to end test which performs the equivalent of the following
$ echo "test" > test.txt
$ git add .
$ git commit -m "Initial commit"
Related
The code below tries to dereference the first entry of a zero size vector
#include <iostream>
#include <vector>
#define WATCH(a) std::cout << #a << ": " << a << std::endl;
int main(int argc, char** argv)
{
std::vector<int> A(0, 0);
WATCH(&A[0])
return 0;
}
This is invalid but compile and run with gcc-11.3.0 for both debug and release build. The build command in debug mode is
g++ -g -rdynamic main.o -o main
Is there a way to tell gcc to not allow this?
I have mnist.loader.hpp header file that opens and reads t10k-images-idx3-ubyte and t10k-labels-idx1-ubyte binary files in a given path using std::ifstream as can be seen in the snippet below:
std::string imagePath = dataDir + std::string("t10k-images-idx3-ubyte");
std::string labelPath = dataDir + std::string("t10k-labels-idx1-ubyte");
std::ifstream imageStream(imagePath, std::ios::binary);
std::ifstream labelStream(labelPath, std::ios::binary);
The path of the directory having those two binary files dataDir is embedded in mnist_caffe.cpp. It could be changed as per my setting in the std::string dataDir = "data/" line.
I set dataDir to /home/mohamed/, then compiled and statically-linked an aarch64 executable out of them and my target is to simulate it on gem5.
The problem:
gem5 always fails to read the files. It gives "Failed to read /home/mohamed/t10k-images-idx3-ubyte".
If we have a look once again at mnist_loader.hpp, we will notice that this error message is due to either the file not being open as or being opened but can't be read :
if (!imageStream.is_open())
{
std::cerr << "Failed to load " << imagePath << std::endl;
return nullptr;
}
or
imageStream.read(reinterpret_cast<char*>(&magic), sizeof(magic));
if (magic != 0x03080000)
{
std::cerr << "Failed to read " << imagePath << std::endl;
return nullptr;
}
or
if (!imageStream.good())
{
std::cerr << "Failed to read " << imagePath << std::endl;
return nullptr;
}
My guess is that gem5 can not open the file in the first place!
My trials:
(I am only interested in opening and reading t10k-images-idx3-ubyte for now)
1- Trying to pass the file to the stdin using -i option: $ ./build/ARM/gem5.opt ./configs/example/se.py -c mnist_caffe -i '/home/mohamed/t10k-images-idx3-ubyte'
2- Using -o: $ ./build/ARM/gem5.opt ./configs/example/se.py -c mnist_caffe -o "-i /home/mohamed/t10k-images-idx3-ubyte"
3- Using --redirects: $ ./build/ARM/gem5.opt ./configs/example/se.py -c /home/mohamed/NNDeploy/ML-examples/armnn-mnist/mnist_caffe --redirects /home/mohamed/t10k-images-idx3-ubyte=/home/mohamed/t10k-images-idx3-ubyte
4- Opening the binary file in the host system using xxd and then passing it to stdin: $ ./build/ARM/gem5.opt ./configs/example/se.py -c ~/NNDeploy/ML-examples/armnn-mnist/mnist_caffe -o " -i /usr/bin/xxd /home/mohamed/t10k-images-idx3-ubyte"
All the above resulted in the same failed-to-read message. I ran out of ideas and it would be great if someone could provide some suggestions!
All I can find on this topic is mentions of FSMoveObjectToTrashSync function, which is now deprecated and no alternative is listed for it.
How to do it from C or Objective-C code?
Use NSFileManager:
https://developer.apple.com/documentation/foundation/nsfilemanager
trashItemAtURL:resultingItemURL:error:
Moves an item to the trash.
In C, you can use AppleScript to move files to the trash. Here's a simple example:
#include <stdio.h>
#include <stdlib.h>
#define PATH "/tmp/"
#define NAME "delete-me.txt"
int main() {
int status;
/* Create a file */
FILE *f;
f = fopen(PATH NAME, "w");
if (!f) {
fputs("Can't create file " PATH NAME "\n", stderr);
return 1;
}
fputs("I love trash\n", f);
fclose(f);
/* Now put it in the trash */
status = system(
"osascript -e 'set theFile to POSIX file \"" PATH NAME "\"' "
"-e 'tell application \"Finder\"' "
"-e 'delete theFile' "
"-e 'end tell' "
">/dev/null"
);
if (status == 0) {
puts("Look in the trash folder for a file called " NAME);
}
else {
puts("Something went wrong. Unable to delete " PATH NAME);
}
return 0;
}
A few notes:
Multi-line scripts have to be sent as multiple -e command line options.
Since osascript insists on printing status messages to the command line console, I've redirected its output to /dev/null. But, if a file of the same name already exists in the trash, then the deleted file will be renamed. If you need to know this name, you'll have to use popen() instead of system() and parse the return string from osascript.
I wrote the following code in a file named test.cpp on godaddy web host:
#include <iostream>
using namespace std;
int main () {
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Hello World - First CGI Program</title>\n";
cout << "</head>\n";
cout << "<body>\n";
cout << "<h2>Hello World! This is my first CGI program</h2>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
And I compile test.cpp on the godaddy host using "g++ test.cpp -o a.cgi".
Then I tried to access the cgi (type "www.XXX.com/a.cgi"), the error code 500 came out. I have no idea what went wrong.
Change the permissions of the file using file manager to make it executable
try www.xxx.com/cgi-bin/a.cgi
changing a.cgi to a.cpp and then check if it works
I have now whittled this down to a minimal test case. Thus far I have been able to determine that this is an issue related to pseudo-terminals which come about with the pipe of ssh. Adding the '-t -t' to the ssh call improved things, in that now, it takes a second call to fgets() to cause the issue. I suspect that the stderr output of the ssh command somehow works into the issue, for now I have redirected stderr to stdout in the ssh code to execute. I do wonder if the "tcgetattr: Invalid argument" error is part of the problem, but am not sure how to get rid of that. It seems to come from the -t -t being present. I believe the -t -t is moving in the right direction, but I have to set up the pseudo terminal for stderr somehow and perhaps the test will work properly?
The Makefile:
test:
gcc -g -DBUILD_MACHINE='"$(shell hostname)"' -c -o test.o test.c
gcc -g -o test test.o
.PHONY: clean
clean:
rm -rf test.o test
The test.c source file:
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
const unsigned int bufSize = 32;
char buf1[bufSize];
char buf2[bufSize];
int ssh = argv[1][0] == 'y';
const char *cmd = ssh ? "ssh -t -t " BUILD_MACHINE " \"ls\" 2>&1" : "ls";
FILE *fPtr = popen(cmd, "r");
if (fPtr == NULL) {
fprintf(stderr,"Unable to spawn command.\n");
perror("popen(3)");
exit(1);
}
printf("Command: %s\n", cmd);
if (feof(fPtr) == 0 && fgets(buf2, bufSize, fPtr) != NULL) {
printf("First result: %s\n", buf2);
if (feof(fPtr) == 0 && fgets(buf2, bufSize, fPtr) != NULL) {
printf("Second result: %s\n", buf2);
int nRead = read(fileno(stdin), buf1, bufSize);
if (nRead == 0) {
printf("???? popen() of ssh consumed the beginning of stdin ????\n");
} else if (nRead > 0) {
if (strncmp("The quick brown fox jumped", buf1, 26) != 0) {
printf("??? Failed ???\n");
} else {
printf("!!!!!!! Without ssh popen() did not consume stdin !!!!!!!\n");
}
}
}
}
}
This shows it running the passing way:
> echo "The quick brown fox jumped" | ./test n
Command: ls
First result: ARCH.linux_26_i86
Second result: Makefile
!!!!!!! Without ssh popen() did not consume stdin !!!!!!!
This shows it running the failing way:
> echo "The quick brown fox jumped" | ./test y
Command: ssh -t -t hostname "ls" 2>&1
First result: tcgetattr: Invalid argument
Second result: %backup%~ gmon.out
???? popen() of ssh consumed the beginning of stdin ????
Okay, I have got this working finally. The secret was to supply /dev/null as the input to my ssh command as follows from the test case above:
const char *cmd
= ssh ? "ssh -t -t " BUILD_MACHINE " \"ls\" 2>&1 < /dev/null" : "ls";
However, while the code works correctly, I get a nasty message which apparently I can ignore for my purposes (although I'd like to make the message go away):
tcgetattr: Inappropriate ioctl for device