Added byline
[anjuta.git] / plugins / project-wizard / install.c
blob833ab5748714abec26efdc5c66bf85def70e63f0
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 install.c
4 Copyright (C) 2004 Sebastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * Handle installation of all files
24 *---------------------------------------------------------------------------*/
26 #include <config.h>
28 #include "install.h"
30 #include "plugin.h"
31 #include "file.h"
32 #include "parser.h"
33 #include "action.h"
35 #include <libanjuta/interfaces/ianjuta-file-loader.h>
36 #include <libanjuta/anjuta-autogen.h>
37 #include <libanjuta/anjuta-launcher.h>
38 #include <libanjuta/anjuta-debug.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <ctype.h>
46 /*---------------------------------------------------------------------------*/
48 #define FILE_BUFFER_SIZE 4096
50 #define AUTOGEN_START_MACRO_LEN 7
51 #define AUTOGEN_MARKER_1 "autogen5"
52 #define AUTOGEN_MARKER_2 "template"
54 /*---------------------------------------------------------------------------*/
56 struct _NPWInstall
58 AnjutaAutogen* gen;
59 NPWFileListParser* file_parser;
60 GList* file_list;
61 GList* current_file;
62 NPWActionListParser* action_parser;
63 GList* action_list;
64 GList* action;
65 AnjutaLauncher* launcher;
66 NPWPlugin* plugin;
67 const gchar* project_file;
68 gboolean success;
71 /*---------------------------------------------------------------------------*/
73 static void on_install_end_install_file (AnjutaAutogen* gen, gpointer data);
74 static void on_run_terminated (AnjutaLauncher* launcher, gint pid, gint status, gulong time, NPWInstall* this);
75 static gboolean npw_install_install_file (NPWInstall* this);
76 static gboolean npw_run_action (NPWInstall* this);
77 static gboolean npw_open_action (NPWInstall* this);
79 /* Helper functions
80 *---------------------------------------------------------------------------*/
82 static gboolean
83 npw_is_autogen_template_file (FILE* tpl)
85 gint len;
86 const gchar* marker[] = {"", AUTOGEN_MARKER_1, AUTOGEN_MARKER_2, NULL};
87 const gchar** key;
88 const gchar* ptr;
89 gint c;
92 for (key = marker; *key != NULL; ++key)
94 /* Skip first whitespace */
97 c = fgetc (tpl);
98 if (c == EOF) return FALSE;
100 while (isspace (c));
102 /* Test start marker, then autogen5, then template */
103 ptr = *key;
104 len = *ptr == '\0' ? AUTOGEN_START_MACRO_LEN : strlen (ptr);
107 if (len == 0) return FALSE;
108 --len;
109 if ((*ptr != '\0') && (tolower (c) != *ptr++)) return FALSE;
110 c = fgetc (tpl);
111 /* FIXME: Test this EOF test */
112 if (c == EOF) return FALSE;
114 while (!isspace (c));
115 if ((**key != '\0') && (len != 0)) return FALSE;
118 return TRUE;
121 static gboolean
122 npw_is_autogen_template (const gchar* filename)
124 FILE* tpl;
125 gboolean autogen;
127 tpl = fopen (filename, "rt");
128 if (tpl == NULL) return FALSE;
130 autogen = npw_is_autogen_template_file (tpl);
131 fclose (tpl);
133 return autogen;
136 static gboolean
137 npw_copy_file (const gchar* destination, const gchar* source)
139 gchar* buffer;
140 FILE* src;
141 FILE* dst;
142 guint len;
143 gboolean ok;
145 buffer = g_new (gchar, FILE_BUFFER_SIZE);
147 /* Copy file */
148 src = fopen (source, "rb");
149 if (src == NULL)
151 return FALSE;
154 dst = fopen (destination, "wb");
155 if (dst == NULL)
157 return FALSE;
160 ok = TRUE;
161 for (;!feof (src);)
163 len = fread (buffer, 1, FILE_BUFFER_SIZE, src);
164 if ((len != FILE_BUFFER_SIZE) && !feof (src))
166 ok = FALSE;
167 break;
170 if (len != fwrite (buffer, 1, len, dst))
172 ok = FALSE;
173 break;
177 fclose (dst);
178 fclose (src);
180 g_free (buffer);
182 return ok;
185 /* Installer object
186 *---------------------------------------------------------------------------*/
188 NPWInstall* npw_install_new (NPWPlugin* plugin)
190 NPWInstall* this;
192 /* Skip if already created */
193 if (plugin->install != NULL) return plugin->install;
195 this = g_new0(NPWInstall, 1);
196 this->gen = anjuta_autogen_new ();
197 this->plugin = plugin;
198 this->success = TRUE;
199 npw_plugin_create_view (plugin);
201 plugin->install = this;
203 return this;
206 void npw_install_free (NPWInstall* this)
208 if (this->file_parser != NULL)
210 npw_file_list_parser_free (this->file_parser);
212 if (this->file_list != NULL)
214 g_list_foreach (this->file_list, (GFunc)npw_file_free, NULL);
215 g_list_free (this->file_list);
217 if (this->action_parser != NULL)
219 npw_action_list_parser_free (this->action_parser);
221 if (this->action_list != NULL)
223 g_list_foreach (this->action_list, (GFunc)npw_action_free, NULL);
224 g_list_free (this->action_list);
226 if (this->launcher != NULL)
228 g_signal_handlers_disconnect_by_func (G_OBJECT (this->launcher), G_CALLBACK (on_run_terminated), this);
229 g_object_unref (this->launcher);
231 g_object_unref (this->gen);
232 this->plugin->install = NULL;
233 g_free (this);
236 gboolean
237 npw_install_set_property (NPWInstall* this, GHashTable* values)
239 anjuta_autogen_write_definition_file (this->gen, values, NULL);
241 return TRUE;
244 gboolean
245 npw_install_set_wizard_file (NPWInstall* this, const gchar* filename)
247 if (this->file_list != NULL)
249 g_list_foreach (this->file_list, (GFunc)npw_file_free, NULL);
250 g_list_free (this->file_list);
251 this->file_list = NULL;
253 if (this->file_parser != NULL)
255 npw_file_list_parser_free (this->file_parser);
257 this->file_parser = npw_file_list_parser_new (filename);
259 anjuta_autogen_set_input_file (this->gen, filename, "[+","+]");
261 return TRUE;
264 gboolean
265 npw_install_set_library_path (NPWInstall* this, const gchar *directory)
267 anjuta_autogen_set_library_path (this->gen, directory);
269 return TRUE;
272 static void
273 on_install_read_action_list (const gchar* output, gpointer data)
275 NPWInstall* this = (NPWInstall*)data;
277 npw_action_list_parser_parse (this->action_parser, output, strlen (output), NULL);
280 static void
281 on_install_end_action (gpointer data)
283 NPWInstall* this = (NPWInstall*)data;
285 for (;;)
287 NPWAction *action;
289 if (this->action == NULL)
291 if (this->success)
293 /* Run action on success only */
294 this->action = g_list_first (this->action_list);
297 else
299 this->action = g_list_next (this->action);
301 if (this->action == NULL)
303 DEBUG_PRINT ("Project wizard done");
304 /* The wizard could have been deactivated when loading the new
305 * project. Hence, the following check.
307 if (anjuta_plugin_is_active (ANJUTA_PLUGIN (this->plugin)))
308 anjuta_plugin_deactivate (ANJUTA_PLUGIN (this->plugin));
309 npw_install_free (this);
310 return;
312 action = (NPWAction *)this->action->data;
314 switch (npw_action_get_type (action))
316 case NPW_RUN_ACTION:
317 npw_run_action (this);
318 return;
319 case NPW_OPEN_ACTION:
320 npw_open_action (this);
321 break;
322 default:
323 break;
328 static void
329 on_install_read_all_action_list (AnjutaAutogen* gen, gpointer data)
331 NPWInstall* this = (NPWInstall*)data;
333 this->action_list = npw_action_list_parser_end_parse (this->action_parser, NULL);
335 on_install_end_install_file (NULL, this);
338 static void
339 on_install_read_file_list (const gchar* output, gpointer data)
341 NPWInstall* this = (NPWInstall*)data;
343 npw_file_list_parser_parse (this->file_parser, output, strlen (output), NULL);
346 static void
347 on_install_read_all_file_list (AnjutaAutogen* gen, gpointer data)
349 NPWInstall* this = (NPWInstall*)data;
351 this->file_list = npw_file_list_parser_end_parse (this->file_parser, NULL);
353 this->current_file = NULL;
354 this->project_file = NULL;
356 if (this->action_list != NULL)
358 g_list_foreach (this->action_list, (GFunc)npw_action_free, NULL);
359 g_list_free (this->action_list);
360 this->action_list = NULL;
362 if (this->action_parser != NULL)
364 npw_action_list_parser_free (this->action_parser);
366 this->action_parser = npw_action_list_parser_new ();
367 anjuta_autogen_set_output_callback (this->gen, on_install_read_action_list, this, NULL);
368 anjuta_autogen_execute (this->gen, on_install_read_all_action_list, this, NULL);
371 static void
372 on_install_end_install_file (AnjutaAutogen* gen, gpointer data)
374 NPWInstall* this = (NPWInstall*)data;
376 /* Warning gen could be invalid */
378 for (;;)
380 NPWFile *file;
382 if (this->current_file == NULL)
384 this->current_file = g_list_first (this->file_list);
386 else
388 NPWFile *file = (NPWFile *)this->current_file->data;
390 if (npw_file_get_execute (file))
392 gint previous;
393 /* Make this file executable */
394 previous = umask (0666);
395 chmod (npw_file_get_destination (file), 0777 & ~previous);
396 umask (previous);
398 if (npw_file_get_project (file))
400 /* Check if project is NULL */
401 this->project_file = npw_file_get_destination (file);
403 this->current_file = g_list_next (this->current_file);
405 if (this->current_file == NULL)
407 /* IAnjutaFileLoader* loader; */
408 /* All files have been installed */
409 if (this->success)
411 npw_plugin_print_view (this->plugin,
412 IANJUTA_MESSAGE_VIEW_TYPE_INFO,
413 _("New project has been created successfully."),
414 "");
416 else
418 npw_plugin_print_view (this->plugin,
419 IANJUTA_MESSAGE_VIEW_TYPE_ERROR,
420 _("New project creation has failed."),
421 "");
423 on_install_end_action (this);
425 return;
427 file = (NPWFile *)this->current_file->data;
428 switch (npw_file_get_type (file))
430 case NPW_FILE:
431 npw_install_install_file (this);
432 return;
433 default:
434 g_warning("Unknown file type %d\n", npw_file_get_type (file));
435 break;
440 gboolean
441 npw_install_launch (NPWInstall* this)
443 anjuta_autogen_set_output_callback (this->gen, on_install_read_file_list, this, NULL);
444 anjuta_autogen_execute (this->gen, on_install_read_all_file_list, this, NULL);
446 return TRUE;
449 static gboolean
450 npw_install_install_file (NPWInstall* this)
452 gchar* buffer;
453 gchar* sep;
454 guint len;
455 const gchar* destination;
456 const gchar* source;
457 gchar* msg;
458 gboolean use_autogen;
459 gboolean ok = TRUE;
460 NPWFile *file = (NPWFile *)this->current_file->data;
463 destination = npw_file_get_destination (file);
464 source = npw_file_get_source (file);
466 /* Check if file already exist */
467 if (g_file_test (destination, G_FILE_TEST_EXISTS))
469 msg = g_strdup_printf (_("Skipping %s: file already exists"), destination);
470 npw_plugin_print_view (this->plugin, IANJUTA_MESSAGE_VIEW_TYPE_WARNING, msg, "");
471 g_free (msg);
472 on_install_end_install_file (this->gen, this);
474 return FALSE;
477 /* Check if autogen is needed */
478 switch (npw_file_get_autogen (file))
480 case NPW_TRUE:
481 use_autogen = TRUE;
482 break;
483 case NPW_FALSE:
484 use_autogen = FALSE;
485 break;
486 case NPW_DEFAULT:
487 use_autogen = npw_is_autogen_template (source);
488 break;
489 default:
490 use_autogen = FALSE;
493 len = strlen (destination) + 1;
494 buffer = g_new (gchar, MAX (FILE_BUFFER_SIZE, len));
495 strcpy (buffer, destination);
496 sep = buffer;
497 for (;;)
499 /* Get directory one by one */
500 sep = strstr (sep,G_DIR_SEPARATOR_S);
501 if (sep == NULL) break;
502 /* Create directory if necessary */
503 *sep = '\0';
504 if ((*buffer != '~') && (*buffer != '\0'))
506 if (!g_file_test (buffer, G_FILE_TEST_EXISTS))
508 if (mkdir (buffer, 0755) == -1)
510 msg = g_strdup_printf (_("Creating %s … Failed to create directory"), destination);
511 ok = FALSE;
512 break;
516 *sep++ = G_DIR_SEPARATOR_S[0];
519 if (ok)
521 if (use_autogen)
523 anjuta_autogen_set_input_file (this->gen, source, NULL, NULL);
524 anjuta_autogen_set_output_file (this->gen, destination);
525 ok = anjuta_autogen_execute (this->gen, on_install_end_install_file, this, NULL);
526 msg = g_strdup_printf (_("Creating %s (using AutoGen)… %s"), destination, ok ? "Ok" : "Fail to Execute");
528 else
530 ok = npw_copy_file (destination, source);
531 msg = g_strdup_printf (_("Creating %s … %s"), destination, ok ? "Ok" : "Fail to copy file");
535 /* Record failure and display error message */
536 if (!ok)
538 this->success = FALSE;
540 npw_plugin_print_view (this->plugin, ok ? IANJUTA_MESSAGE_VIEW_TYPE_INFO : IANJUTA_MESSAGE_VIEW_TYPE_ERROR, msg, "");
541 g_free (msg);
543 /* Next file is called automatically if autogen succeed */
544 if (!ok || !use_autogen)
545 on_install_end_install_file (this->gen, this);
547 return ok;
550 static void
551 on_run_terminated (AnjutaLauncher* launcher, gint pid, gint status, gulong time, NPWInstall* this)
553 on_install_end_action (this);
556 static void
557 on_run_output (AnjutaLauncher* launcher, AnjutaLauncherOutputType type, const gchar* output, gpointer data)
559 NPWInstall* this = (NPWInstall*)data;
561 npw_plugin_append_view (this->plugin, output);
564 static gboolean
565 npw_run_action (NPWInstall* this)
567 gchar *msg;
568 NPWAction *action = (NPWAction *)this->action->data;
570 if (this->launcher == NULL)
572 this->launcher = anjuta_launcher_new ();
574 g_signal_connect (G_OBJECT (this->launcher), "child-exited", G_CALLBACK (on_run_terminated), this);
575 /* The %s is a name of a unix command line, by example
576 * cp foobar.c project */
577 msg = g_strdup_printf (_("Executing: %s"), npw_action_get_command (action));
578 npw_plugin_print_view (this->plugin, IANJUTA_MESSAGE_VIEW_TYPE_INFO, msg, "");
579 g_free (msg);
581 return anjuta_launcher_execute (this->launcher, npw_action_get_command (action), on_run_output, this);
584 static gboolean
585 npw_open_action (NPWInstall* this)
587 IAnjutaFileLoader* loader;
588 NPWAction *action = (NPWAction *)this->action->data;
590 loader = anjuta_shell_get_interface (ANJUTA_PLUGIN (this->plugin)->shell, IAnjutaFileLoader, NULL);
591 if (loader)
593 GFile* file = g_file_new_for_path (npw_action_get_file (action));
594 ianjuta_file_loader_load (loader, file, FALSE, NULL);
595 g_object_unref (file);
597 return TRUE;
600 return FALSE;