Passed
Push — master ( c3e4a8...0dc18f )
by Scrutinizer
01:43
created

rewriteNameSpace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
#!/usr/bin/env php
2
<?php
3
/**
4
 * This script will re-write the file name and contents from the template ones to user given one.
5
 *
6
 * Package name:
7
 *   The package name will be replaced from "HelloWorld" to the parent directory name. Which is
8
 *   the repository's directory name.
9
 * User/Vendor name:
10
 *   - If the user/vendor name is given from STDIN (such as via pipe) or the first argument, that
11
 *     name will rename all the string "KEINOS" to the provided one.
12
 *   - If not then it will ask the user/vendor name and replace "KEINOS" to the provided one.
13
 *
14
 * NOTE:
15
 *   This script must be called only from the command `composer create-project`.
16
 *   Check "scripts" key value in `/composer.json`.
17
 */
18
19
echo '------------------------------------------------------------' . PHP_EOL;
20
echo ' Initializing package via "composer create-project" command' . PHP_EOL;
21
echo '------------------------------------------------------------' . PHP_EOL;
22
23
const DIR_SEP = DIRECTORY_SEPARATOR;
24
25
// ============================================================================
26
//  Preparation
27
// ============================================================================
28
29
// List of files that are expected to exist in the root dir of the package
30
$list_files_in_root_expect = [
31
    'README.md',
32
    'LICENSE',
33
    'Dockerfile',
34
    'composer.json',
35
    'src',
36
];
37
$path_dir_package = getPathDirRootOfPackage($list_files_in_root_expect);
38
39
// Set package name to replace
40
$name_pkg_from = 'HelloWorld';
41
$name_pkg_to   = ucfirst(basename($path_dir_package));
42
43
// Set names of vendor to replace
44
$name_vendor_from = 'KEINOS';
45
$name_vendor_to   = getNameVendor(); // Get or ask user the name of vendor
46
47
// Set namespace
48
$namespace_from = "${name_vendor_from}/${name_pkg_from}";
49
$namespace_to   = "${name_vendor_to}/${name_pkg_to}";
50
51
// List of files and dirs to exclude when renaming
52
$list_exclude_file = [
53
    basename(__FILE__),
54
    '.git',
55
    'vendor',
56
];
57
58
// List of pairs to replace names from-to
59
$list_before_after = [
60
    [
61
        'before' => $name_vendor_from,
62
        'after'  => $name_vendor_to,
63
    ],
64
    [
65
        'before' => $name_pkg_from,
66
        'after'  => $name_pkg_to,
67
    ],
68
];
69
70
// ============================================================================
71
//  Main
72
// ============================================================================
73
74
// Get only files
75
$list_path_file_replace = getListPathFilesAll($path_dir_package, $list_exclude_file);
76
77
try {
78
    foreach ($list_path_file_replace as $path_file_current) {
79
        // Rewrite contents
80
        if (is_file($path_file_current)) {
81
            echo 'Now renaming contents... ';
82
            // Rewrite contents
83
            rewriteFileContents($path_file_current, $list_before_after);
84
        }
85
86
        // Rewrite file name
87
        rewriteFileName($path_file_current, $name_pkg_from, $name_pkg_to);
88
    }
89
90
    $last_line = exec('composer dump-autoload', $output, $return_var);
91
    if ($return_var !== 0) {
92
        $msg_error = implode(PHP_EOL, $output);
93
        throw new \RuntimeException($msg_error);
94
    }
95
} catch (\RuntimeException $e) {
96
    echo 'ERROR: ', PHP_EOL,  $e->getMessage(), "\n";
97
}
98
99
exit(0);
100
101
// ============================================================================
102
//  Functions
103
// ============================================================================
104
105
function askAgainIfSure($string)
106
{
107
    echo '- Are you sure? (Y/n/quit):';
108
    $input  = strtolower(trim(fgets(STDIN)));
109
    $result = $input[0];
110
111
    if ($result === 'y') {
112
        return true;
113
    }
114
115
    if ($result === 'q') {
116
        throw new \RuntimeException(
117
            "Initialization aborted." . PHP_EOL .
118
            "- Vendor name and namespaces NOT changed." . PHP_EOL .
119
            "- You will need to change them your own." . PHP_EOL
120
        );
121
    }
122
123
    return false;
124
}
125
126
function askUserNameVendor()
127
{
128
    global $name_vendor_from;
129
130
    do {
131
        echo '-----------------------' . PHP_EOL;
132
        echo ' Your name/Vendor name ' . PHP_EOL;
133
        echo '-----------------------' . PHP_EOL;
134
        echo "  NOTE: This will replace all the string \"${name_vendor_from}\" to yours. Including namespaces." . PHP_EOL;
135
        echo '- Input your name/vendor name: ';
136
        $name_vendor = trim(fgets(STDIN));
137
138
        if (! empty($name_vendor)) {
139
            echo PHP_EOL . 'Vendor name will be: ', $name_vendor, PHP_EOL;
140
            $name_vendor = (askAgainIfSure($name_vendor)) ? $name_vendor : '';
141
        } else {
142
            echo '* ERROR: Vendor name empty. Try again.' . PHP_EOL;
143
            sleep(1);
144
        }
145
    } while (empty(trim($name_vendor)));
146
147
    return $name_vendor;
148
}
149
150
function getListPathFilesAll(string $path, array $list_exclude): array
151
{
152
    $path_dir = getPathDirReal($path);
153
    $pattern  = $path_dir . DIR_SEP . '{*,.[!.]*,..?*}'; // Search dot files/dir also but not '.' and '..'
154
    $result   = [];
155
156
    foreach (glob($pattern, GLOB_BRACE) as $path_file) {
157
        if (in_array(basename($path_file), $list_exclude)) {
158
            continue;
159
        }
160
        if (is_dir($path_file)) {
161
            $result = array_merge($result, getListPathFilesAll($path_file, $list_exclude));
162
            continue;
163
        }
164
        if (! is_writable($path_file)) {
165
            throw new \RuntimeException(
166
                'Given path is not writable.' . PHP_EOL .
167
                 '- Path: ' . $path_file . PHP_EOL
168
            );
169
        }
170
171
        $result[] = $path_file;
172
    }
173
174
    return $result;
175
}
176
177
function getNameFromArg()
178
{
179
    global $argc, $argv;
180
181
    if ($argc === 1) {
182
        return '';
183
    }
184
185
    return $argv[1];
186
}
187
188
function getNameFromSTDIN()
189
{
190
    return (\posix_isatty(STDIN)) ? '' : \file_get_contents('php://stdin');
191
}
192
193
function getNameVendor()
194
{
195
    // STDIN
196
    $name_vendor = trim(getNameFromSTDIN());
197
    if (! empty($name_vendor)) {
198
        return $name_vendor;
199
    }
200
    // ARG
201
    $name_vendor = trim(getNameFromArg());
202
    if (! empty($name_vendor)) {
203
        return $name_vendor;
204
    }
205
    // User input
206
    $name_vendor = askUserNameVendor();
207
    if (! empty($name_vendor)) {
208
        return $name_vendor;
209
    }
210
}
211
212
function getPathDirRootOfPackage($list_files_in_root)
213
{
214
    // Expecting this file is set under /init in the package
215
    $path_dir_parent = dirname(__DIR__);
216
217
    foreach ($list_files_in_root as $name_file) {
218
        $path = $path_dir_parent . DIR_SEP . $name_file;
219
        if (! \file_exists($path)) {
220
            throw new \RuntimeException("Expected file in root dir of the package is missing.\n Missing file: ${path}\n");
221
        }
222
    }
223
224
    return $path_dir_parent;
225
}
226
227
function getPathDirReal(string $path): string
228
{
229
    if (empty(trim($path))) {
230
        throw new InvalidArgumentException('Empty argument. The given path is empty.');
231
    }
232
233
    $path = \realpath($path);
234
    if ($path === false) {
235
        throw new InvalidArgumentException('Invalid path given. Path: ' . $path);
236
    }
237
    if (! is_dir($path)) {
238
        throw new InvalidArgumentException('Given path is not a directory. Path: ' . $path);
239
    }
240
    if (! is_readable($path)) {
241
        throw new \RuntimeException('Given path is not readable. Path: ' . $path);
242
    }
243
244
    return $path;
245
}
246
247
function rewriteFileContents(string $path_file, array $list_before_after)
248
{
249
    if (! is_file($path_file)) {
250
        throw new \RuntimeException('Given path is not a file. Path: ' . $path_file);
251
    }
252
253
    $data_original = \file_get_contents($path_file);
254
    if ($data_original === false) {
255
        throw new \RuntimeException('Fail to read file. Path: ' . $path_file);
256
    }
257
258
    $flag_needs_save = false;
259
260
    $data_target     = rewriteNameSpace($data_original);
261
    $flag_needs_save = ($data_target !== $data_original);
262
263
    foreach ($list_before_after as $substitute) {
264
        $from = $substitute['before'];
265
        $to   = $substitute['after'];
266
        if (strpos($data_target, $from) !== false) {
267
            $data_target     = str_replace($from, $to, $data_target);
268
            $flag_needs_save = true;
269
        }
270
    }
271
272
    if ($flag_needs_save === true) {
273
        $result = \file_put_contents($path_file, $data_target, LOCK_EX);
274
        if ($result === false) {
275
            throw new \RuntimeException('Fail to save/overwrite data to file:' . $path_file);
276
        }
277
        echo 'OK ... ' . $path_file . PHP_EOL;
278
    } else {
279
        echo 'SKIP ... ' . $path_file . PHP_EOL;
280
    }
281
}
282
283
function rewriteFileName($path_file_from, $name_file_from, $name_file_to)
284
{
285
    // Find if the file name includes package name. Skip if not.
286
    $name_file_target = basename($path_file_from);
287
    if (strpos($name_file_target, $name_file_from) === false) {
288
        return false;
289
    }
290
    // New path to re-write
291
    $name_file_new = str_replace($name_file_from, $name_file_to, $name_file_target);
292
    $path_file_new = dirname($path_file_from) . DIR_SEP . $name_file_new;
293
294
    // Rename!
295
    $result = rename($path_file_from, $path_file_new);
296
    if ($result === false) {
297
        throw new \RuntimeException(
298
            'Fail to change file name.' . PHP_EOL .
299
            '- Original file path: ' . $path_file_from . PHP_EOL .
300
            '- Name to be replaces: ' . $name_file_to . PHP_EOL
301
        );
302
    }
303
}
304
305
function rewriteNameSpace($script)
306
{
307
    global $namespace_from, $namespace_to;
308
309
    return str_replace($namespace_from, $namespace_to, $script);
310
}
311