Skip to content

Commit 5064bd2

Browse files
committed
Intial version of git
0 parents  commit 5064bd2

File tree

7 files changed

+244
-0
lines changed

7 files changed

+244
-0
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto

.gitignore

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Prerequisites
2+
*.d
3+
4+
# Compiled Object files
5+
*.slo
6+
*.lo
7+
*.o
8+
*.obj
9+
10+
# Precompiled Headers
11+
*.gch
12+
*.pch
13+
14+
# Compiled Dynamic libraries
15+
*.so
16+
*.dylib
17+
*.dll
18+
19+
# Fortran module files
20+
*.mod
21+
*.smod
22+
23+
# Compiled Static libraries
24+
*.lai
25+
*.la
26+
*.a
27+
*.lib
28+
29+
# Executables
30+
*.exe
31+
*.out
32+
*.app
33+
server
34+
35+
# CMake
36+
CMakeLists.txt.user
37+
CMakeCache.txt
38+
CMakeFiles
39+
CMakeScripts
40+
Testing
41+
Makefile
42+
cmake_install.cmake
43+
install_manifest.txt
44+
compile_commands.json
45+
CTestTestfile.cmake
46+
_deps
47+
48+
build/
49+
vcpkg_installed
50+
.vscode/

CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
cmake_minimum_required(VERSION 3.13)
2+
3+
project(git-starter-cpp)
4+
5+
set(CMAKE_CXX_STANDARD 23) # Enable the C++23 standard
6+
7+
file(GLOB_RECURSE SOURCE_FILES src/*.cpp src/*.hpp)
8+
9+
add_executable(git ${SOURCE_FILES})
10+
11+
find_package(OpenSSL REQUIRED)
12+
target_link_libraries(git OpenSSL::SSL OpenSSL::Crypto)
13+
14+
target_link_libraries(git -lz)

src/Server.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include <iostream>
2+
#include <filesystem>
3+
#include <fstream>
4+
#include <string>
5+
#include <zlib.h>
6+
#include <vector>
7+
#include <openssl/sha.h>
8+
9+
10+
using namespace std;
11+
12+
#define fs filesystem
13+
14+
15+
string sha_file(string basicString);
16+
void compressFile(string basicString, uLong *pInt, unsigned char data[20]);
17+
void compressFile(const string data, uLong *bound, unsigned char *dest) ;
18+
void hash_object(string file);
19+
20+
21+
int main(int argc, char *argv[])
22+
{
23+
// Flush after every cout / cerr
24+
cout << unitbuf;
25+
cerr << unitbuf;
26+
27+
// You can use print statements as follows for debugging, they'll be visible when running tests.
28+
cerr << "Logs from your program will appear here!\n";
29+
30+
// Uncomment this block to pass the first stage
31+
//
32+
if (argc < 2) {
33+
cerr << "No command provided.\n";
34+
return EXIT_FAILURE;
35+
}
36+
37+
string command = argv[1];
38+
// cout << "Command: " << command << '\n';
39+
40+
if (command == "init") {
41+
try {
42+
fs::create_directory(".git");
43+
fs::create_directory(".git/objects");
44+
fs::create_directory(".git/refs");
45+
46+
ofstream headFile(".git/HEAD");
47+
if (headFile.is_open()) {
48+
headFile << "ref: refs/heads/main\n";
49+
headFile.close();
50+
} else {
51+
cerr << "Failed to create .git/HEAD file.\n";
52+
return EXIT_FAILURE;
53+
}
54+
55+
cout << "Initialized git directory\n";
56+
} catch (const fs::filesystem_error& e) {
57+
cerr << e.what() << '\n';
58+
return EXIT_FAILURE;
59+
}
60+
}else if (command == "cat--file" || command == "cat-file") {
61+
if (argc < 4 || (string(argv[2]) != "-p")) {
62+
cerr << "No object hash provided.\n";
63+
cerr << "required `-p <blob_sha>`\n";
64+
return EXIT_FAILURE;
65+
}
66+
67+
const auto blobHash = string_view(argv[3],40);
68+
const auto blobDir = blobHash.substr(0, 2);
69+
const auto blobName = blobHash.substr(2);
70+
const auto blobPath = fs::path(".git") / "objects" / blobDir / blobName;
71+
72+
auto input = ifstream(blobPath);
73+
74+
if(!input.is_open()){
75+
cerr << "Failed to open" << blobPath << "file.\n";
76+
return EXIT_FAILURE;
77+
}
78+
79+
const auto blobData = string(istreambuf_iterator<char>(input), istreambuf_iterator<char>());
80+
auto buf = string();
81+
buf.resize(blobData.size());
82+
while(true){
83+
auto len = buf.size();
84+
if(auto res = uncompress((uint8_t*)buf.data(), &len, (uint8_t*)blobData.data(), blobData.size()); res == Z_BUF_ERROR){
85+
buf.resize(len*2);
86+
break;
87+
}
88+
else if(res != Z_OK){
89+
cerr << "Failed to decompress blob data.\n";
90+
return EXIT_FAILURE;
91+
}
92+
else{
93+
buf.resize(len);
94+
break;
95+
}
96+
}
97+
cout << string_view(buf).substr(buf.find('\0')+1)<<flush;
98+
}else if (command == "hash--object" || command == "hash-object"){
99+
if(argc < 4 || (string(argv[2]) != "-w")){
100+
cerr << "No file provided.\n";
101+
cerr << "required `-w <file>`\n";
102+
return EXIT_FAILURE;
103+
}
104+
105+
string hash = argv[3];
106+
hash_object(hash);
107+
108+
}
109+
else {
110+
cerr << "Unknown command " << command << '\n';
111+
return EXIT_FAILURE;
112+
}
113+
114+
return EXIT_SUCCESS;
115+
}
116+
117+
118+
119+
void hash_object(string file) {
120+
ifstream t(file);
121+
stringstream data;
122+
data << t.rdbuf();
123+
string content = "blob " + to_string(data.str().length()) + '\0' + data.str();
124+
// Calculate SHA1 hash
125+
string buffer = sha_file(content);
126+
// Compress blob content
127+
uLong bound = compressBound(content.size());
128+
unsigned char compressedData[bound];
129+
compressFile(content, &bound, compressedData);
130+
// Write compressed data to .git/objects
131+
string dir = ".git/objects/" + buffer.substr(0,2);
132+
fs::create_directory(dir);
133+
string objectPath = dir + "/" + buffer.substr(2);
134+
ofstream objectFile(objectPath, ios::binary);
135+
objectFile.write((char *)compressedData, bound);
136+
objectFile.close();
137+
}
138+
void compressFile(const string data, uLong *bound, unsigned char *dest) {
139+
compress(dest, bound, (const Bytef *)data.c_str(), data.size());
140+
}
141+
string sha_file(string data) {
142+
unsigned char hash[20];
143+
SHA1((unsigned char *)data.c_str(), data.size(), hash);
144+
stringstream ss;
145+
ss << hex << setfill('0');
146+
for (const auto& byte : hash) {
147+
ss << setw(2) << static_cast<int>(byte);
148+
}
149+
cout << ss.str() << endl;
150+
return ss.str();
151+
}

vcpkg-configuration.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"default-registry": {
3+
"kind": "git",
4+
"baseline": "c4af3593e1f1aa9e14a560a09e45ea2cb0dfd74d",
5+
"repository": "https://github.com/microsoft/vcpkg"
6+
},
7+
"registries": [
8+
{
9+
"kind": "artifact",
10+
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
11+
"name": "microsoft"
12+
}
13+
]
14+
}

vcpkg.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"dependencies": []
3+
}

your_program.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
3+
4+
set -e
5+
(
6+
cd "$(dirname "$0")"
7+
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake
8+
cmake --build ./build
9+
)
10+
11+
exec $(dirname "$0")/build/git "$@"

0 commit comments

Comments
 (0)