summaryrefslogtreecommitdiff
path: root/Userland/DevTools/HackStudio/Git/GitRepo.cpp
blob: 50506fd13a31fa450e641e90f800678f92254021 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "GitRepo.h"
#include <LibCore/Command.h>
#include <stdio.h>
#include <stdlib.h>

namespace HackStudio {

GitRepo::CreateResult GitRepo::try_to_create(const LexicalPath& repository_root)
{
    if (!git_is_installed()) {
        return { CreateResult::Type::GitProgramNotFound, nullptr };
    }
    if (!git_repo_exists(repository_root)) {
        return { CreateResult::Type::NoGitRepo, nullptr };
    }

    return { CreateResult::Type::Success, adopt(*new GitRepo(repository_root)) };
}

RefPtr<GitRepo> GitRepo::initialize_repository(const LexicalPath& repository_root)
{
    auto res = command_wrapper({ "init" }, repository_root);
    if (res.is_null())
        return {};

    VERIFY(git_repo_exists(repository_root));
    return adopt(*new GitRepo(repository_root));
}

Vector<LexicalPath> GitRepo::unstaged_files() const
{
    auto modified = modified_files();
    auto untracked = untracked_files();
    modified.append(move(untracked));
    return modified;
}
//
Vector<LexicalPath> GitRepo::staged_files() const
{
    auto raw_result = command({ "diff", "--cached", "--name-only" });
    if (raw_result.is_null())
        return {};
    return parse_files_list(raw_result);
}

Vector<LexicalPath> GitRepo::modified_files() const
{
    auto raw_result = command({ "ls-files", "--modified", "--exclude-standard" });
    if (raw_result.is_null())
        return {};
    return parse_files_list(raw_result);
}

Vector<LexicalPath> GitRepo::untracked_files() const
{
    auto raw_result = command({ "ls-files", "--others", "--exclude-standard" });
    if (raw_result.is_null())
        return {};
    return parse_files_list(raw_result);
}

Vector<LexicalPath> GitRepo::parse_files_list(const String& raw_result)
{
    auto lines = raw_result.split('\n');
    Vector<LexicalPath> files;
    for (const auto& line : lines) {
        files.empend(line);
    }
    return files;
}

String GitRepo::command(const Vector<String>& command_parts) const
{
    return command_wrapper(command_parts, m_repository_root);
}

String GitRepo::command_wrapper(const Vector<String>& command_parts, const LexicalPath& chdir)
{
    return Core::command("git", command_parts, chdir);
}

bool GitRepo::git_is_installed()
{
    return !command_wrapper({ "--help" }, LexicalPath("/")).is_null();
}

bool GitRepo::git_repo_exists(const LexicalPath& repo_root)
{
    return !command_wrapper({ "status" }, repo_root).is_null();
}

bool GitRepo::stage(const LexicalPath& file)
{
    return !command({ "add", file.string() }).is_null();
}

bool GitRepo::unstage(const LexicalPath& file)
{
    return !command({ "reset", "HEAD", "--", file.string() }).is_null();
}

bool GitRepo::commit(const String& message)
{
    return !command({ "commit", "-m", message }).is_null();
}

Optional<String> GitRepo::original_file_content(const LexicalPath& file) const
{
    return command({ "show", String::formatted("HEAD:{}", file) });
}

Optional<String> GitRepo::unstaged_diff(const LexicalPath& file) const
{
    return command({ "diff", file.string().characters() });
}

bool GitRepo::is_tracked(const LexicalPath& file) const
{
    auto res = command({ "ls-files", file.string() });
    if (res.is_null())
        return false;
    return !res.is_empty();
}

}