Onur Özgür ÖZKAN

Php, Ruby, Kebab, Git Geek

Develop a Simple Installer for Kebab Project on PHP CLI - II

Last post, i introduced Kebab Project Installer on PHP CLI. First of all i want to say that i changed some codes because i was writing the code when i was writing the post in the same time. This morning i coded review and improve the codes. First of all i want to say that you can improve the codes, you can add new repository from git. But these codes are for trial not for products. If you want to use them at products, please first test them. We will start a project for Kebab Installer. You can find more codes and examples there.

First i created a final Helper Class and add getLine and showMenu static methods.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
final class Helper
{
    public static function getLine()
    {
        $handle = fopen ("php://stdin","r");
        return trim(fgets($handle));
    }

    public static function showMenu()
    {
        echo "What do you install?\n"
          . "1. Kebab \n";
    }
}

Developer can use the methods like above because they are static methods.

1
2
$input = Helper::getLine();
Helper::showMenu();

Then i try to write a simple factory design pattern for GitHub Repository Installer. First i write a interface for Repository classes. Every repository class has to install() function.

1
2
3
4
interface IInstaller
{
    public function install();
}

Of course we should define the what is repository. So i write a abstract class Repository whose properties are name, path, url and branch.

1
2
3
4
5
6
7
abstract class Repository
{
    protected $name;
    protected $path;
    protected $url;
    protected $branch;
}

After that i extend KebabProject Class from Repository Abstract Class and implement IInstaller interface.

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
class KebabProject extends Repository implements IInstaller
{
    protected $name = 'KebabProject';
    protected $path;
    protected $url = 'https://github.com/lab2023/kebab-project.git';
    protected $branch = 'origin/HEAD';

    public function __construct()
    {
        if (!is_dir($this->path = dirname(__FILE__) . '/www')) {
            mkdir($this->path, 0777, true);
        }
    }

    public function install()
    {
        echo "> Installing $this->name\n";

        if (!is_dir($this->path . '/.git')) {
           system(sprintf('git clone %s %s', escapeshellarg($this->url), escapeshellarg($this->path)));
        }

        system(sprintf('cd %s && git fetch origin && git reset --hard %s', escapeshellarg($this->path), escapeshellarg($this->branch)));
    }
}

In this class $name is class name, $path is install directory, $url is git’s url from github, $branch is revision. At __construct method we check the $path and give value, if there isn’t directory, make a directory with mkdir method.

In install methed, first we check $this->path is a directory, if not, we run git clone $url $path method. If $this->path is a directory we do nothing and pass other line. Then we change directory to $this->path and git fetch and git reset.

Of course we need a factory class and method for run this classes.

1
2
3
4
5
6
7
class Installer
{
    public static function factory($type)
    {
        return new $type();
    }
}

This Installer class return the Repository classes. It use like that

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Start here
Helper::showMenu();

switch (Helper::getLine()) {
    case "1":
        echo "You wanna install Kebab Project\n";
        $installer = Installer::factory('KebabProject');
        $installer->install();
        break;
    default:
        echo "\033[31mWrong choice\033[37m\r\n";
}

exit;

If we concat all the codes, we’ll get

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
#!/usr/bin/env php
<?php

final class Helper
{
    public static function getLine()
    {
        $handle = fopen ("php://stdin","r");
        return trim(fgets($handle));
    }

    public static function showMenu()
    {
        echo "What do you install?\n"
          . "1. Kebab \n";
    }
}

interface IInstaller
{
    public function install();
}

abstract class Repository
{
    protected $name;
    protected $path;
    protected $url;
    protected $branch;
}

class KebabProject extends Repository implements IInstaller
{
    protected $name = 'KebabProject';
    protected $path;
    protected $url = 'https://github.com/lab2023/kebab-project.git';
    protected $branch = 'origin/HEAD';

    public function __construct()
    {
        if (!is_dir($this->path = dirname(__FILE__) . '/www')) {
            mkdir($this->path, 0777, true);
        }
    }

    public function install()
    {
        echo "> Installing $this->name\n";

        if (!is_dir($this->path . '/.git')) {
           system(sprintf('git clone %s %s', escapeshellarg($this->url), escapeshellarg($this->path)));
        }

        system(sprintf('cd %s && git fetch origin && git reset --hard %s', escapeshellarg($this->path), escapeshellarg($this->branch)));
    }
}

class Installer
{
    public static function factory($type)
    {
        return new $type();
    }
}


// Start here
Helper::showMenu();

switch (Helper::getLine()) {
    case "1":
        echo "You wanna install Kebab Project\n";
        $installer = Installer::factory('KebabProject');
        $installer->install();
        break;
    default:
        echo "\033[31mWrong choice\033[37m\r\n";
}

exit;

Best Regards.