1<?php
2/*
3 * Copyright 2020 Google LLC
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy of
7 * the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17
18namespace Google\Task;
19
20use Composer\Script\Event;
21use Symfony\Component\Filesystem\Filesystem;
22use Symfony\Component\Finder\Finder;
23use InvalidArgumentException;
24
25class Composer
26{
27  /**
28   * @param Event $event Composer event passed in for any script method
29   * @param Filesystem $filesystem Optional. Used for testing.
30   */
31  public static function cleanup(
32      Event $event,
33      Filesystem $filesystem = null
34  ) {
35    $composer = $event->getComposer();
36    $extra = $composer->getPackage()->getExtra();
37    $servicesToKeep = isset($extra['google/apiclient-services']) ?
38      $extra['google/apiclient-services'] : [];
39    if ($servicesToKeep) {
40      $vendorDir = $composer->getConfig()->get('vendor-dir');
41      $serviceDir = sprintf(
42          '%s/google/apiclient-services/src/Google/Service',
43          $vendorDir
44      );
45      if (!is_dir($serviceDir)) {
46        // path for google/apiclient-services >= 0.200.0
47        $serviceDir = sprintf(
48            '%s/google/apiclient-services/src',
49            $vendorDir
50        );
51      }
52      self::verifyServicesToKeep($serviceDir, $servicesToKeep);
53      $finder = self::getServicesToRemove($serviceDir, $servicesToKeep);
54      $filesystem = $filesystem ?: new Filesystem();
55      if (0 !== $count = count($finder)) {
56        $event->getIO()->write(
57            sprintf(
58                'Removing %s google services',
59                $count
60            )
61        );
62        foreach ($finder as $file) {
63          $realpath = $file->getRealPath();
64          $filesystem->remove($realpath);
65          $filesystem->remove($realpath . '.php');
66        }
67      }
68    }
69  }
70
71  /**
72   * @throws InvalidArgumentException when the service doesn't exist
73   */
74  private static function verifyServicesToKeep(
75      $serviceDir,
76      array $servicesToKeep
77  ) {
78    $finder = (new Finder())
79        ->directories()
80        ->depth('== 0');
81
82    foreach ($servicesToKeep as $service) {
83      if (!preg_match('/^[a-zA-Z0-9]*$/', $service)) {
84        throw new InvalidArgumentException(
85            sprintf(
86                'Invalid Google service name "%s"',
87                $service
88            )
89        );
90      }
91      try {
92        $finder->in($serviceDir . '/' . $service);
93      } catch (InvalidArgumentException $e) {
94        throw new InvalidArgumentException(
95            sprintf(
96                'Google service "%s" does not exist or was removed previously',
97                $service
98            )
99        );
100      }
101    }
102  }
103
104  private static function getServicesToRemove(
105      $serviceDir,
106      array $servicesToKeep
107  ) {
108    // find all files in the current directory
109    return (new Finder())
110        ->directories()
111        ->depth('== 0')
112        ->in($serviceDir)
113        ->exclude($servicesToKeep);
114  }
115}
116