Serenity Operating System
1/*
2 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "GitRepo.h"
8#include <LibCore/Command.h>
9
10namespace HackStudio {
11
12GitRepo::CreateResult GitRepo::try_to_create(DeprecatedString const& repository_root)
13{
14 if (!git_is_installed()) {
15 return { CreateResult::Type::GitProgramNotFound, nullptr };
16 }
17 if (!git_repo_exists(repository_root)) {
18 return { CreateResult::Type::NoGitRepo, nullptr };
19 }
20
21 return { CreateResult::Type::Success, adopt_ref(*new GitRepo(repository_root)) };
22}
23
24RefPtr<GitRepo> GitRepo::initialize_repository(DeprecatedString const& repository_root)
25{
26 auto res = command_wrapper({ "init" }, repository_root);
27 if (res.is_null())
28 return {};
29
30 VERIFY(git_repo_exists(repository_root));
31 return adopt_ref(*new GitRepo(repository_root));
32}
33
34Vector<DeprecatedString> GitRepo::unstaged_files() const
35{
36 auto modified = modified_files();
37 auto untracked = untracked_files();
38 modified.extend(move(untracked));
39 return modified;
40}
41//
42Vector<DeprecatedString> GitRepo::staged_files() const
43{
44 auto raw_result = command({ "diff", "--cached", "--name-only" });
45 if (raw_result.is_null())
46 return {};
47 return parse_files_list(raw_result);
48}
49
50Vector<DeprecatedString> GitRepo::modified_files() const
51{
52 auto raw_result = command({ "ls-files", "--modified", "--exclude-standard" });
53 if (raw_result.is_null())
54 return {};
55 return parse_files_list(raw_result);
56}
57
58Vector<DeprecatedString> GitRepo::untracked_files() const
59{
60 auto raw_result = command({ "ls-files", "--others", "--exclude-standard" });
61 if (raw_result.is_null())
62 return {};
63 return parse_files_list(raw_result);
64}
65
66Vector<DeprecatedString> GitRepo::parse_files_list(DeprecatedString const& raw_result)
67{
68 auto lines = raw_result.split('\n');
69 Vector<DeprecatedString> files;
70 for (auto const& line : lines) {
71 files.empend(line);
72 }
73 return files;
74}
75
76DeprecatedString GitRepo::command(Vector<DeprecatedString> const& command_parts) const
77{
78 return command_wrapper(command_parts, m_repository_root);
79}
80
81DeprecatedString GitRepo::command_wrapper(Vector<DeprecatedString> const& command_parts, DeprecatedString const& chdir)
82{
83 auto result = Core::command("git", command_parts, LexicalPath(chdir));
84 if (result.is_error() || result.value().exit_code != 0)
85 return {};
86 return result.value().output;
87}
88
89bool GitRepo::git_is_installed()
90{
91 return !command_wrapper({ "--help" }, "/").is_null();
92}
93
94bool GitRepo::git_repo_exists(DeprecatedString const& repo_root)
95{
96 return !command_wrapper({ "status" }, repo_root).is_null();
97}
98
99bool GitRepo::stage(DeprecatedString const& file)
100{
101 return !command({ "add", file }).is_null();
102}
103
104bool GitRepo::unstage(DeprecatedString const& file)
105{
106 return !command({ "reset", "HEAD", "--", file }).is_null();
107}
108
109bool GitRepo::commit(DeprecatedString const& message)
110{
111 return !command({ "commit", "-m", message }).is_null();
112}
113
114Optional<DeprecatedString> GitRepo::original_file_content(DeprecatedString const& file) const
115{
116 return command({ "show", DeprecatedString::formatted("HEAD:{}", file) });
117}
118
119Optional<DeprecatedString> GitRepo::unstaged_diff(DeprecatedString const& file) const
120{
121 return command({ "diff", file.characters() });
122}
123
124bool GitRepo::is_tracked(DeprecatedString const& file) const
125{
126 auto res = command({ "ls-files", file });
127 if (res.is_null())
128 return false;
129
130 return !res.is_empty();
131}
132
133}