GitProcessor::forcePush()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Kasifi\Gitaski;
4
5
use DateInterval;
6
use DateTime;
7
use Exception;
8
use Symfony\Component\Console\Output\OutputInterface;
9
use Symfony\Component\Console\Style\SymfonyStyle;
10
use Symfony\Component\Process\Process;
11
12
class GitProcessor
13
{
14
    /** @var bool */
15
    private $force;
16
17
    /** @var SymfonyStyle */
18
    private $io;
19
20
    private $splitContentCursor = 0;
21
22
    /** @var array */
23
    private $commitMessages;
24
25
    /** @var array */
26
    private $splitContent = [];
27
28
    /** @var string */
29
    private $outputFilename;
30
31
    /** @var string */
32
    private $githubRepositoryUrl;
33
34
    /** @var string */
35
    private $workspacePath;
36
37
    /**
38
     * GitHelper constructor.
39
     *
40
     * @param string  $githubRepositoryUrl
41
     * @param boolean $force
42
     * @param string  $inputFilePath
43
     * @param string  $outputFilename
44
     * @param array   $commitMessages
45
     */
46
    public function __construct(
47
        $githubRepositoryUrl,
48
        $force,
49
        $inputFilePath,
50
        $outputFilename,
51
        array $commitMessages
52
    ) {
53
        $this->githubRepositoryUrl = $githubRepositoryUrl;
54
        $this->force = $force;
55
        $this->outputFilename = $outputFilename;
56
        $this->commitMessages = $commitMessages;
57
        $splitContent = file_get_contents($inputFilePath);
58
        $this->splitContent = explode(' ', $splitContent);
59
        $workspacePath = sys_get_temp_dir() . '/gitaski' . rand(0, 1000000);
60
        $this->workspacePath = $workspacePath;
61
        mkdir($this->workspacePath);
62
    }
63
64
    /**
65
     * @return void
66
     */
67
    public function initLocalRepository()
68
    {
69
        $this->execCmd('git init && git remote set-url origin ' . $this->githubRepositoryUrl, true);
70
    }
71
72
    /**
73
     * @param DateTime $date
74
     */
75
    public function addCommit(DateTime $date)
76
    {
77
        $filePath = $this->workspacePath . '/' . $this->outputFilename;
78
        $message = $this->commitMessages[array_rand($this->commitMessages)];
79
80
        if (!file_exists($filePath)) {
81
            touch($filePath);
82
        }
83
84
        $this->splitContentCursor++;
85
86
        $content = implode(' ', array_slice($this->splitContent, 0, $this->splitContentCursor));
87
88
        $message = sprintf($message, $this->splitContent[$this->splitContentCursor - 1]);
89
        $message = str_replace('\'', '-', $message);
90
        $message = str_replace('"', '-', $message);
91
92
        file_put_contents($filePath, $content);
93
94
        $dateStr = $date->format('r');
95
96
        $this->execCmd('git add ' . $this->outputFilename . ' && git commit -m \'' . $message . '\' --date="' . $dateStr . '"');
97
    }
98
99
    public function clean()
100
    {
101
        $this->execCmd('rm -rf ' . $this->workspacePath);
102
    }
103
104
    /**
105
     * @param DateTime $date
106
     *
107
     * @return DateTime
108
     */
109
    public function getPreviousSunday(DateTime $date)
110
    {
111
        return $this->sub($date, $date->format('w'));
112
    }
113
114
    /**
115
     * @param SymfonyStyle $io
116
     */
117
    public function setIo(SymfonyStyle $io)
118
    {
119
        $this->io = $io;
120
    }
121
122
    /**
123
     * @return void
124
     */
125
    private function forcePush()
126
    {
127
        $this->execCmd('git push --force --set-upstream origin master');
128
    }
129
130
    /**
131
     * @param array    $symbol
132
     * @param DateTime $lastSunday
133
     *
134
     * @throws Exception
135
     */
136
    public function writeSymbol($symbol, DateTime $lastSunday)
137
    {
138
        $dates = $this->getDatesFromSymbol($symbol, $lastSunday);
139
        foreach ($dates as $date) {
140
            for ($i = 0; $i < $date['count']; $i++) {
141
                $this->addCommit($date['date']);
142
                echo '.';
143
            }
144
        }
145
        echo "\n";
146
        if ($this->force) {
147
            $this->forcePush();
148
            $this->io->comment('Git local checkout has been created and pushed to the origin repository. You can now view it online.');
149
        } else {
150
            $this->io->warning('Git local checkout has been created but not sent. Use --force to really push it to the github account.');
151
        }
152
        $this->io->success('Done.');
153
    }
154
155
    /**
156
     * @param array    $symbol
157
     * @param DateTime $lastSunday
158
     *
159
     * @return array
160
     * @throws Exception
161
     */
162
    private function getDatesFromSymbol($symbol, DateTime $lastSunday)
163
    {
164
        $dates = [];
165
166
        $width = count($symbol[0]);
167
        $height = count($symbol);
168
169
        if ($height != 7) {
170
            throw new Exception('Line height != 7');
171
        }
172
173
        $firstSunday = $this->sub($lastSunday, $width * $height);
174
175
        foreach ($symbol as $lineNumber => $line) {
176
            foreach ($line as $colNumber => $commitCount) {
177
                $daysGapWithFirstSunday = $lineNumber + $colNumber * 7;
178
                $date = $this->add($firstSunday, $daysGapWithFirstSunday);
179
                $dates[$date->format('Y-m-d')] = ['date' => $date, 'count' => $commitCount];
180
            }
181
        }
182
        ksort($dates);
183
184
        return $dates;
185
    }
186
187
    /**
188
     * @param DateTime $date
189
     * @param integer  $days
190
     *
191
     * @return DateTime
192
     */
193
    private function sub(DateTime $date, $days)
194
    {
195
        $date = clone $date;
196
197
        return $date->sub(new DateInterval('P' . $days . 'D'));
198
    }
199
200
    /**
201
     * @param DateTime $date
202
     * @param integer  $days
203
     *
204
     * @return DateTime
205
     */
206
    private function add(DateTime $date, $days)
207
    {
208
        $date = clone $date;
209
210
        return $date->add(new DateInterval('P' . $days . 'D'));
211
    }
212
213
    /**
214
     * @param string $cmd
215
     * @param bool   $ignoreErrors
216
     *
217
     * @throws Exception
218
     */
219
    private function execCmd($cmd, $ignoreErrors = false)
220
    {
221
        $cmd = 'cd ' . $this->workspacePath . ' && ' . $cmd;
222
        if ($this->io->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
223
            $this->io->comment($cmd);
224
        }
225
        $process = new Process($cmd);
226
227
        $process->run(function ($type, $buffer) use ($ignoreErrors) {
228
            if (Process::ERR === $type) {
229
                if ($ignoreErrors) {
230
                    if ($this->io->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
231
                        $this->io->comment($buffer);
232
                    }
233
                } else {
234
                    $this->io->error($buffer);
235
                }
236
            } else {
237
                if ($this->io->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
238
                    $this->io->comment($buffer);
239
                }
240
            }
241
        });
242
243
        if (!$ignoreErrors && !$process->isSuccessful()) {
244
            throw new Exception($process->getOutput() . $process->getErrorOutput());
245
        }
246
    }
247
}