44
55use Composer \Composer ;
66use Composer \IO \IOInterface ;
7- use Composer \Util \Filesystem ;
8- use Composer \Util \RemoteFilesystem ;
9- use DrupalComposer \DrupalScaffold \FileFetcher ;
10- use Symfony \Component \Filesystem \Filesystem as SymfonyFilesystem ;
7+ use Composer \Util \Filesystem as ComposerFilesystem ;
8+ use Symfony \Component \Filesystem \Filesystem ;
119
1210class Handler
1311{
@@ -22,6 +20,11 @@ class Handler
2220 */
2321 protected $ io ;
2422
23+ /**
24+ * @var \Symfony\Component\Filesystem\Filesystem
25+ */
26+ protected $ filesystem ;
27+
2528 /**
2629 * Handler constructor.
2730 *
@@ -32,6 +35,7 @@ public function __construct(Composer $composer, IOInterface $io)
3235 {
3336 $ this ->composer = $ composer ;
3437 $ this ->io = $ io ;
38+ $ this ->filesystem = new Filesystem ();
3539 }
3640
3741 /**
@@ -41,28 +45,207 @@ public function __construct(Composer $composer, IOInterface $io)
4145 */
4246 public function onPostCmdEvent (\Composer \Script \Event $ event )
4347 {
44- $ this ->downloadScaffold ();
48+ $ event ->getIO ()->write ("Updating Shepherd scaffold files. " );
49+ $ this ->updateShepherdScaffoldFiles ();
50+ $ event ->getIO ()->write ("Creating necessary directories. " );
51+ $ this ->createDirectories ();
52+ $ event ->getIO ()->write ("Creating settings.php file if not present. " );
53+ $ this ->createSettingsFile ();
54+ $ event ->getIO ()->write ("Creating services.yml file if not present. " );
55+ $ this ->createServicesFile ();
4556 }
4657
4758 /**
48- * Downloads Shepherd Drupal scaffold files.
59+ * Update the Shepherd scaffold files.
4960 */
50- public function downloadScaffold ()
61+ public function updateShepherdScaffoldFiles ()
5162 {
52- $ source = 'https://raw.githubusercontent.com/universityofadelaide/shepherd-drupal-scaffold/{version}/{path} ' ;
53- $ filenames = [
54- 'dsh ' ,
55- 'RoboFileBase.php ' ,
56- ];
57- $ version = 'master ' ;
58- $ destination = dirname ($ this ->composer ->getConfig ()
59- ->get ('vendor-dir ' ));
60-
61- $ fetcher = new FileFetcher (
62- new RemoteFilesystem ($ this ->io ),
63- $ source ,
64- $ filenames
63+ $ packagePath = $ this ->getPackagePath ();
64+ $ projectPath = $ this ->getProjectPath ();
65+
66+ // Always copy and replace these files.
67+ $ this ->copyFiles (
68+ $ packagePath ,
69+ $ projectPath ,
70+ [
71+ 'dsh ' ,
72+ 'RoboFileBase.php ' ,
73+ ],
74+ true
6575 );
66- $ fetcher ->fetch ($ version , $ destination );
76+
77+ // Only copy these files if they do not exist at the destination.
78+ $ this ->copyFiles (
79+ $ packagePath ,
80+ $ projectPath ,
81+ [
82+ 'docker-compose.yml ' ,
83+ 'RoboFile.php ' ,
84+ ]
85+ );
86+ }
87+
88+ /**
89+ * Ensure necessary directories exist.
90+ */
91+ public function createDirectories ()
92+ {
93+ $ root = $ this ->getDrupalRootPath ();
94+ $ dirs = [
95+ 'modules ' ,
96+ 'profiles ' ,
97+ 'themes ' ,
98+ ];
99+
100+ // Required for unit testing.
101+ foreach ($ dirs as $ dir ) {
102+ if (!$ this ->filesystem ->exists ($ root . '/ ' . $ dir )) {
103+ $ this ->filesystem ->mkdir ($ root . '/ ' . $ dir );
104+ $ this ->filesystem ->touch ($ root . '/ ' . $ dir . '/.gitkeep ' );
105+ }
106+ }
107+ }
108+
109+ /**
110+ * Create settings.php file and inject Shepherd-specific settings.
111+ *
112+ * Note: does nothing if the file already exists.
113+ */
114+ public function createSettingsFile ()
115+ {
116+ $ root = $ this ->getDrupalRootPath ();
117+
118+ // If the settings.php is not present, and the default version is...
119+ if (!$ this ->filesystem ->exists ($ root . '/sites/default/settings.php ' ) && $ this ->filesystem ->exists ($ root . '/sites/default/default.settings.php ' )) {
120+ $ this ->filesystem ->copy ($ root . '/sites/default/default.settings.php ' , $ root . '/sites/default/settings.php ' );
121+ $ this ->filesystem ->chmod ($ root . '/sites/default/settings.php ' , 0666 );
122+
123+ $ shepherdSettings = "\n/** \n * START SHEPHERD CONFIG \n */ \n" .
124+ "\$databases['default']['default'] = array ( \n" .
125+ " 'database' => getenv('DATABASE_NAME'), \n" .
126+ " 'username' => getenv('DATABASE_USER'), \n" .
127+ " 'password' => getenv('DATABASE_PASSWORD_FILE') ? file_get_contents(getenv('DATABASE_PASSWORD_FILE')) : getenv('DATABASE_PASSWORD'), \n" .
128+ " 'host' => getenv('DATABASE_HOST'), \n" .
129+ " 'port' => getenv('DATABASE_PORT') ?: '3306', \n" .
130+ " 'driver' => getenv('DATABASE_DRIVER') ?: 'mysql', \n" .
131+ " 'prefix' => getenv('DATABASE_PREFIX') ?: '', \n" .
132+ " 'collation' => getenv('DATABASE_COLLATION') ?: 'utf8mb4_general_ci', \n" .
133+ " 'namespace' => getenv('DATABASE_NAMESPACE') ?: 'Drupal \\\\Core \\\\Database \\\\Driver \\\\mysql', \n" .
134+ "); \n" .
135+ "\$settings['file_private_path'] = getenv('PRIVATE_DIR'); \n" .
136+ "\$settings['hash_salt'] = getenv('HASH_SALT') ?: ' " . str_replace (['+ ' , '/ ' , '= ' ], ['- ' , '_ ' , '' ], base64_encode (random_bytes (55 ))) . "'; \n" .
137+ "\$config_directories['sync'] = getenv('CONFIG_SYNC_DIRECTORY') ?: 'sites/default/files/config_ " . str_replace (['+ ' , '/ ' , '= ' ], ['- ' , '_ ' , '' ], base64_encode (random_bytes (55 ))) . "/sync'; \n" .
138+ "if (! is_dir( \$app_root . '/' . \$config_directories['sync'])) mkdir( \$app_root . '/' . \$config_directories['sync'], 0777, true); \n" .
139+ "\$settings['shepherd_site_id'] = getenv('SHEPHERD_SITE_ID'); \n" .
140+ "\$settings['shepherd_url'] = getenv('SHEPHERD_URL'); \n" .
141+ "\$settings['shepherd_token'] = getenv('SHEPHERD_TOKEN_FILE') ? file_get_contents(getenv('SHEPHERD_TOKEN_FILE')) : getenv('SHEPHERD_TOKEN'); \n" .
142+ "/** \n * END SHEPHERD CONFIG \n */ \n" .
143+ "\n" .
144+ "/** \n * START LOCAL CONFIG \n */ \n" .
145+ "if (file_exists(__DIR__ . '/settings.local.php')) { \n" .
146+ " include __DIR__ . '/settings.local.php'; \n" .
147+ "} \n" .
148+ "/** \n * END LOCAL CONFIG \n */ \n"
149+ ;
150+
151+ // Append Shepherd-specific environment variable settings to settings.php.
152+ file_put_contents (
153+ $ root . '/sites/default/settings.php ' ,
154+ $ shepherdSettings ,
155+ FILE_APPEND
156+ );
157+ }
158+ }
159+
160+ /**
161+ * Create services.yml file if not present.
162+ */
163+ public function createServicesFile ()
164+ {
165+ $ root = $ this ->getDrupalRootPath ();
166+
167+ if (!$ this ->filesystem ->exists ($ root . '/sites/default/services.yml ' ) && $ this ->filesystem ->exists ($ root . '/sites/default/default.services.yml ' )) {
168+ $ this ->filesystem ->copy ($ root . '/sites/default/default.services.yml ' , $ root . '/sites/default/services.yml ' );
169+ $ this ->filesystem ->chmod ($ root . '/sites/default/services.yml ' , 0666 );
170+ }
171+ }
172+
173+ /**
174+ * Copy files from origin to destination, optionally overwritting existing.
175+ *
176+ * @param bool $overwriteExisting
177+ * If true, replace existing files. Defaults to false.
178+ */
179+ public function copyFiles ($ origin , $ destination , $ filenames , $ overwriteExisting = false )
180+ {
181+ foreach ($ filenames as $ filename ) {
182+ // Skip copying files that already exist at the destination.
183+ if (! $ overwriteExisting && $ this ->filesystem ->exists ($ destination . '/ ' . $ filename )) {
184+ continue ;
185+ }
186+ $ this ->filesystem ->copy (
187+ $ origin . '/ ' . $ filename ,
188+ $ destination . '/ ' . $ filename ,
189+ true
190+ );
191+ }
192+ }
193+
194+ /**
195+ * Get the path to the vendor directory.
196+ *
197+ * E.g. /home/user/code/project/vendor
198+ *
199+ * @return string
200+ */
201+ public function getVendorPath ()
202+ {
203+ // Load ComposerFilesystem to get access to path normalisation.
204+ $ composerFilesystem = new ComposerFilesystem ();
205+
206+ $ config = $ this ->composer ->getConfig ();
207+ $ composerFilesystem ->ensureDirectoryExists ($ config ->get ('vendor-dir ' ));
208+ $ vendorPath = $ composerFilesystem ->normalizePath (realpath ($ config ->get ('vendor-dir ' )));
209+
210+ return $ vendorPath ;
211+ }
212+
213+ /**
214+ * Get the path to the project directory.
215+ *
216+ * E.g. /home/user/code/project
217+ *
218+ * @return string
219+ */
220+ public function getProjectPath ()
221+ {
222+ $ projectPath = dirname ($ this ->getVendorPath ());
223+ return $ projectPath ;
224+ }
225+
226+ /**
227+ * Get the path to the package directory.
228+ *
229+ * E.g. /home/user/code/project/vendor/universityofadelaide/shepherd-drupal-scaffold
230+ *
231+ * @return string
232+ */
233+ public function getPackagePath ()
234+ {
235+ $ packagePath = $ this ->getVendorPath () . '/universityofadelaide/shepherd-drupal-scaffold ' ;
236+ return $ packagePath ;
237+ }
238+
239+ /**
240+ * Get the path to the Drupal root directory.
241+ *
242+ * E.g. /home/user/code/project/web
243+ *
244+ * @return string
245+ */
246+ public function getDrupalRootPath ()
247+ {
248+ $ drupalRootPath = $ this ->getProjectPath () . '/web ' ;
249+ return $ drupalRootPath ;
67250 }
68251}
0 commit comments