Commit 68be4c2b authored by Sebastien Granjoux's avatar Sebastien Granjoux

project-wizard: Allow to install and open a compressed project template

parent ceb8141f
......@@ -1462,7 +1462,25 @@ gboolean
anjuta_util_is_project_file (const gchar *filename)
{
gsize len = strlen (filename);
return (len > 8) && (strcmp (filename + len - 7, ".anjuta") == 0);
return ((len > 8) && (strcmp (filename + len - 7, ".anjuta") == 0));
}
/**
* anjuta_util_is_template_file:
* @filename: the file name
*
* Return TRUE if the file is an template project file. It is implemented by
* checking only the file extension. So it does not check the existence
* of the file. But it is working on an URI if it does not containt a
* fragment.
*
* Returns: TRUE if the file is a template file, else FALSE
*/
gboolean
anjuta_util_is_template_file (const gchar *filename)
{
gsize len = strlen (filename);
return ((len > 9) && (strcmp (filename + len - 8, ".wiz.tgz") == 0));
}
/**
......
......@@ -121,6 +121,7 @@ gchar* anjuta_util_str_middle_truncate (const gchar *string,
guint truncate_length);
gboolean anjuta_util_is_project_file (const gchar *filename);
gboolean anjuta_util_is_template_file (const gchar *filename);
gchar* anjuta_util_get_file_mime_type (GFile *file);
gchar* anjuta_util_get_local_path_from_uri (const gchar *uri);
......
......@@ -9,4 +9,9 @@
<glob pattern="*.anjuta"/>
<glob pattern="*.prj"/>
</mime-type>
<mime-type type="application/x-anjuta-compressed-project-template">
<sub-class-of type="application/x-compressed-tar"/>
<comment>Anjuta IDE Compressed Project Template</comment>
<glob pattern="*.wiz.tgz"/>
</mime-type>
</mime-info>
......@@ -60,7 +60,9 @@ libanjuta_project_wizard_la_SOURCES= \
install.c \
install.h \
autogen.c \
autogen.h
autogen.h \
tar.c \
tar.h
EXTRA_DIST = \
$(plugin_in_files) \
......
......@@ -3,8 +3,11 @@ _Name=Project Assistant
_Description=Project Assistant
Location=anjuta-project-wizard:NPWPlugin
Icon=anjuta-project-wizard-plugin-48.png
Interfaces=IAnjutaWizard
Interfaces=IAnjutaFile,IAnjutaWizard
UserActivatable=no
[File Loader]
SupportedMimeTypes=application/x-anjuta-compressed-project-template
[Wizard]
_Title=Project
......@@ -357,7 +357,7 @@ cb_druid_insert_project_page (gpointer value, gpointer user_data)
/* Fill project selection page */
static gboolean
npw_druid_fill_selection_page (NPWDruid* druid)
npw_druid_fill_selection_page (NPWDruid* druid, const gchar *directory)
{
gchar* dir;
const gchar * const * sys_dir;
......@@ -370,23 +370,31 @@ npw_druid_fill_selection_page (NPWDruid* druid)
/* Create list of projects */
druid->header_list = npw_header_list_new ();
/* Read project template in user directory,
* normally ~/.local/share/anjuta/project,
* the first template read override the others */
dir = g_build_filename (g_get_user_data_dir (), "anjuta", "project", NULL);
npw_header_list_readdir (&druid->header_list, dir);
g_free (dir);
/* Read project template in system directory */
for (sys_dir = g_get_system_data_dirs (); *sys_dir != NULL; sys_dir++)
if (directory != NULL)
{
dir = g_build_filename (*sys_dir, "anjuta", "project", NULL);
npw_header_list_readdir (&druid->header_list, PROJECT_WIZARD_DIRECTORY);
g_free (dir);
/* Read project template only in specified directory */
npw_header_list_readdir (&druid->header_list, directory);
}
else
{
/* Read project template in user directory,
* normally ~/.local/share/anjuta/project,
* the first template read override the others */
dir = g_build_filename (g_get_user_data_dir (), "anjuta", "project", NULL);
npw_header_list_readdir (&druid->header_list, dir);
g_free (dir);
/* Read project template in system directory */
for (sys_dir = g_get_system_data_dirs (); *sys_dir != NULL; sys_dir++)
{
dir = g_build_filename (*sys_dir, "anjuta", "project", NULL);
npw_header_list_readdir (&druid->header_list, dir);
g_free (dir);
}
/* Read anjuta installation directory */
npw_header_list_readdir (&druid->header_list, PROJECT_WIZARD_DIRECTORY);
/* Read anjuta installation directory */
npw_header_list_readdir (&druid->header_list, PROJECT_WIZARD_DIRECTORY);
}
if (g_list_length (druid->header_list) == 0)
{
......@@ -1008,7 +1016,7 @@ on_druid_finish (GtkAssistant* assistant, NPWDruid* druid)
}
static GtkWidget*
npw_druid_create_assistant (NPWDruid* druid)
npw_druid_create_assistant (NPWDruid* druid, const gchar *directory)
{
AnjutaShell *shell;
GtkBuilder *builder;
......@@ -1046,7 +1054,7 @@ npw_druid_create_assistant (NPWDruid* druid)
g_signal_connect(G_OBJECT(assistant), "key-press-event", G_CALLBACK(on_project_wizard_key_press_event), druid);
/* Setup project selection page */
if (!npw_druid_fill_selection_page (druid))
if (!npw_druid_fill_selection_page (druid, directory))
{
return NULL;
}
......@@ -1117,7 +1125,7 @@ npw_druid_add_default_property (NPWDruid* druid)
*---------------------------------------------------------------------------*/
NPWDruid*
npw_druid_new (NPWPlugin* plugin)
npw_druid_new (NPWPlugin* plugin, const gchar *directory)
{
NPWDruid* druid;
......@@ -1138,7 +1146,7 @@ npw_druid_new (NPWPlugin* plugin)
druid->plugin = plugin;
druid->error_extra_widget = NULL;
if (npw_druid_create_assistant (druid) == NULL)
if (npw_druid_create_assistant (druid, directory) == NULL)
{
npw_druid_free (druid);
......
......@@ -28,7 +28,7 @@
struct _NPWPlugin;
typedef struct _NPWDruid NPWDruid;
NPWDruid* npw_druid_new (struct _NPWPlugin* plugin);
NPWDruid* npw_druid_new (struct _NPWPlugin* plugin, const gchar *directory);
void npw_druid_free (NPWDruid* druid);
void npw_druid_show (NPWDruid* druid);
......
......@@ -28,9 +28,116 @@
#include "plugin.h"
#include "druid.h"
#include "tar.h"
#include <libanjuta/anjuta-debug.h>
#include <libanjuta/interfaces/ianjuta-wizard.h>
#include <libanjuta/interfaces/ianjuta-file.h>
/* Private functions
*---------------------------------------------------------------------------*/
static void
npw_open_project_template (GFile *destination, GFile *tarfile, gpointer data, GError *error)
{
NPWPlugin *plugin = (NPWPlugin *)data;
if (error != NULL)
{
gchar *tarname = g_file_get_path (tarfile);
anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (plugin)->shell),_("Unable to extrat project template %s: %s"), tarname, error->message);
}
else
{
/* Show the project wizard dialog, loading only the new projects */
gchar *path;
path = g_file_get_path (destination);
npw_plugin_show_wizard (plugin, path);
g_free (path);
}
}
static gboolean
npw_install_project_template_with_callback (NPWPlugin *plugin, GFile *file, NPWTarCompleteFunc callback, GError **error)
{
GFileInputStream *stream;
gchar *name;
gchar *ext;
gchar *path;
GFile *dest;
gboolean ok;
GError *err = NULL;
/* Check if tarfile exist */
stream = g_file_read (file, NULL, error);
if (stream == NULL)
{
return FALSE;
}
g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL);
/* Get name without extension */
name = g_file_get_basename (file);
ext = strchr (name, '.');
if (ext != NULL) *ext = '\0';
/* Create a directory for template */
path = g_build_filename (g_get_user_data_dir (), "anjuta", "project", name, NULL);
g_free (name);
dest = g_file_new_for_path (path);
g_free (path);
ok = g_file_make_directory_with_parents (dest, NULL, &err);
if (err != NULL)
{
if (err->code == G_IO_ERROR_EXISTS)
{
/* Allow to overwrite directories */
ok = TRUE;
g_error_free (err);
}
else
{
g_object_unref (dest);
return FALSE;
}
}
ok = npw_tar_extract (dest, file, callback, plugin, error);
g_object_unref (dest);
return ok;
}
/* Public functions
*---------------------------------------------------------------------------*/
/* Display the project wizard selection dialog using only templates in the
* specified directory if non NULL */
gboolean
npw_plugin_show_wizard (NPWPlugin *plugin, const gchar *directory)
{
if (plugin->install != NULL)
{
/* New project wizard is busy copying project file */
}
else if (plugin->druid == NULL)
{
/* Create a new project wizard druid */
npw_druid_new (plugin, directory);
}
if (plugin->druid != NULL)
{
/* New project wizard druid is waiting for user inputs */
npw_druid_show (plugin->druid);
}
return TRUE;
}
/*---------------------------------------------------------------------------*/
......@@ -100,26 +207,13 @@ npw_plugin_class_init (GObjectClass *klass)
klass->finalize = npw_plugin_finalize;
}
/* IAnjutaWizard implementation
*---------------------------------------------------------------------------*/
static void
iwizard_activate (IAnjutaWizard *wiz, GError **err)
{
NPWPlugin *plugin = ANJUTA_PLUGIN_NPW (wiz);
if (plugin->install != NULL)
{
/* New project wizard is busy copying project file */
}
else if (plugin->druid == NULL)
{
/* Create a new project wizard druid */
npw_druid_new (plugin);
}
if (plugin->druid != NULL)
{
/* New project wizard druid is waiting for user inputs */
npw_druid_show (plugin->druid);
}
npw_plugin_show_wizard (ANJUTA_PLUGIN_NPW (wiz), NULL);
}
static void
......@@ -128,7 +222,32 @@ iwizard_iface_init (IAnjutaWizardIface *iface)
iface->activate = iwizard_activate;
}
/* IAnjutaFile implementation
*---------------------------------------------------------------------------*/
static void
ifile_open (IAnjutaFile *ifile, GFile* file, GError **error)
{
NPWPlugin *plugin = ANJUTA_PLUGIN_NPW (ifile);
npw_install_project_template_with_callback (plugin, file, npw_open_project_template, error);
}
static GFile*
ifile_get_file (IAnjutaFile* ifile, GError** error)
{
return NULL;
}
static void
ifile_iface_init(IAnjutaFileIface *iface)
{
iface->open = ifile_open;
iface->get_file = ifile_get_file;
}
ANJUTA_PLUGIN_BEGIN (NPWPlugin, npw_plugin);
ANJUTA_PLUGIN_ADD_INTERFACE (ifile, IANJUTA_TYPE_FILE);
ANJUTA_PLUGIN_ADD_INTERFACE (iwizard, IANJUTA_TYPE_WIZARD);
ANJUTA_PLUGIN_END;
......
......@@ -52,4 +52,6 @@ IAnjutaMessageView* npw_plugin_create_view (NPWPlugin* plugin);
void npw_plugin_append_view (NPWPlugin* plugin, const gchar* text);
void npw_plugin_print_view (NPWPlugin* plugin, IAnjutaMessageViewType type, const gchar* summary, const gchar* details);
gboolean npw_plugin_show_wizard (NPWPlugin *plugin, const gchar *template_dir);
#endif
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
tar.c
Copyright (C) 2010 Sebastien Granjoux
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include "tar.h"
#include <libanjuta/interfaces/ianjuta-wizard.h>
/*---------------------------------------------------------------------------*/
#define TMP_DEF_FILENAME "NPWDEFXXXXXX"
#define TMP_TPL_FILENAME "NPWTPLXXXXXX"
#define FILE_BUFFER_SIZE 4096
/* Type
*---------------------------------------------------------------------------*/
typedef struct _NPWTarPacket NPWTarPacket;
struct _NPWTarPacket
{
gint stdout;
gint stderr;
gpointer callback;
gpointer data;
GFile *tarfile;
GFile *destination;
};
/* Helper functions
*---------------------------------------------------------------------------*/
/* Tar Packet object
*---------------------------------------------------------------------------*/
static void
npw_tar_packet_free (NPWTarPacket *pack)
{
g_object_unref (pack->tarfile);
if (pack->destination) g_object_unref (pack->destination);
g_free (pack);
}
/* Public functions
*---------------------------------------------------------------------------*/
static void
on_tar_listed (GPid pid,
gint status,
gpointer data)
{
NPWTarPacket *pack = (NPWTarPacket *)data;
if (pack->callback != NULL)
{
GIOChannel *output;
GList *list;
GString *line;
GIOStatus status;
list = NULL;
line = g_string_new (NULL);
output = g_io_channel_unix_new (pack->stdout);
do
{
gsize terminator;
status = g_io_channel_read_line_string (output, line, &terminator, NULL);
if (status == G_IO_STATUS_NORMAL)
{
g_string_truncate (line, terminator);
list = g_list_prepend (list, g_strdup (line->str));
continue;
}
}
while (status == G_IO_STATUS_AGAIN);
g_io_channel_close (output);
g_string_free (line, TRUE);
list = g_list_reverse (list);
((NPWTarListFunc)pack->callback) (pack->tarfile, list, pack->data, NULL);
g_list_foreach (list, (GFunc)g_free, NULL);
g_list_free (list);
}
g_spawn_close_pid(pid);
}
static void
on_tar_completed (GPid pid,
gint status,
gpointer data)
{
NPWTarPacket *pack = (NPWTarPacket *)data;
if (pack->callback != NULL)
{
GError *error = NULL;
if (status != 0)
{
GIOChannel *stderr;
gchar *message;
gsize length;
stderr = g_io_channel_unix_new (pack->stderr);
g_io_channel_read_to_end (stderr, &message, &length, &error);
if (error != NULL)
{
error = g_error_new_literal (IANJUTA_WIZARD_ERROR, 0, message);
}
g_io_channel_close (stderr);
}
((NPWTarCompleteFunc)pack->callback) (pack->destination, pack->tarfile, pack->data, error);
g_clear_error (&error);
}
g_spawn_close_pid(pid);
}
/* Public functions
*---------------------------------------------------------------------------*/
gboolean
npw_tar_list (GFile *tarfile, NPWTarListFunc list, gpointer data, GError **error)
{
gchar *argv [] = {"tar", "--force-local", "--no-wildcards", "-tzf", NULL, NULL};
gchar *prog;
gchar *filename;
GPid pid;
gboolean ok;
NPWTarPacket *pack;
/* Use gtar if available */
prog = g_find_program_in_path ("gtar");
filename = g_file_get_path (tarfile);
argv[4] = filename;
/* Execute tar command asynchronously */
pack = g_new0(NPWTarPacket, 1);
pack->callback = (gpointer)list;
pack->data = data;
pack->tarfile = g_object_ref (tarfile);
ok = g_spawn_async_with_pipes (NULL, argv, NULL,
G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
NULL, NULL,
&pid,
NULL,
&pack->stdout,
NULL,
error);
if (ok)
{
g_child_watch_add_full (G_PRIORITY_HIGH_IDLE, pid, on_tar_listed, pack, (GDestroyNotify)npw_tar_packet_free);
}
g_free (filename);
g_free (prog);
return ok;
}
gboolean
npw_tar_extract (GFile *destination, GFile *tarfile, NPWTarCompleteFunc complete, gpointer data, GError **error)
{
gchar *argv [] = {"tar", "--force-local", "--no-wildcards", "-C", NULL, "-xzf", NULL, NULL};
gchar *prog;
gchar *filename;
gchar *dirname;
GPid pid;
gboolean ok;
NPWTarPacket *pack;
/* Use gtar if available */
prog = g_find_program_in_path ("gtar");
dirname = g_file_get_path (destination);
argv[4] = dirname;
filename = g_file_get_path (tarfile);
argv[6] = filename;
/* Execute tar command asynchronously */
pack = g_new0(NPWTarPacket, 1);
pack->callback = (gpointer)complete;
pack->data = data;
pack->tarfile = g_object_ref (tarfile);
pack->destination = g_object_ref (destination);
ok = g_spawn_async_with_pipes (NULL, argv, NULL,
G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
NULL, NULL,
&pid,
NULL,
NULL,
&pack->stderr,
error);
if (ok)
{
g_child_watch_add_full (G_PRIORITY_HIGH_IDLE, pid, on_tar_completed, pack, (GDestroyNotify)npw_tar_packet_free);
}
g_free (filename);
g_free (dirname);
g_free (prog);
return ok;
}
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
tar.h
Copyright (C) 2010 Sebastien Granjoux
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __TAR_H__
#define __TAR_H__
#include <glib.h>
#include <gio/gio.h>
typedef void (*NPWTarListFunc) (GFile *tarfile, GList *list, gpointer data, GError *error);
typedef void (*NPWTarCompleteFunc) (GFile *destination, GFile *tarfile, gpointer data, GError *error);
gboolean npw_tar_list (GFile *tarfile, NPWTarListFunc list, gpointer data, GError **error);
gboolean npw_tar_extract (GFile *destination, GFile *tarfile, NPWTarCompleteFunc complete, gpointer data, GError **error);
#endif
......@@ -242,6 +242,7 @@ anjuta_new (gchar *prog_name, gchar **files, gboolean no_splash,
GFile *session_profile;
gchar *remembered_plugins;
gchar *project_uri = NULL;
gchar *template_uri = NULL;
gchar *profile_name = NULL;
GError *error = NULL;
......@@ -328,6 +329,7 @@ anjuta_new (gchar *prog_name, gchar **files, gboolean no_splash,
session_dir = USER_SESSION_PATH_NEW;
project_uri = extract_project_from_session (session_dir);
template_uri = NULL;
session = anjuta_session_new (session_dir);
anjuta_session_clear (session);
......@@ -344,6 +346,11 @@ anjuta_new (gchar *prog_name, gchar **files, gboolean no_splash,
g_free (project_uri);
project_uri = g_strdup (*node);
}
else if (anjuta_util_is_template_file (*node))
{
g_free (template_uri);
template_uri = g_strdup (*node);
}
else
{
files_load = g_list_prepend (files_load, *node);
......@@ -401,16 +408,16 @@ anjuta_new (gchar *prog_name, gchar **files, gboolean no_splash,
g_signal_connect (profile_manager, "profile-scoped",
G_CALLBACK (on_profile_scoped), app);
/* Load project file */
if (project_uri)
if ((project_uri != NULL) && (template_uri == NULL))
{
GFile* file = g_file_new_for_uri (project_uri);
IAnjutaFileLoader *loader;
loader = anjuta_shell_get_interface (ANJUTA_SHELL (app),
IAnjutaFileLoader, NULL);
ianjuta_file_loader_load (loader, file, FALSE, NULL);
g_free (project_uri);
g_object_unref (file);
}
g_free (project_uri);
anjuta_profile_manager_thaw (profile_manager, &error);
if (error)
......@@ -424,5 +431,18 @@ anjuta_new (gchar *prog_name, gchar **files, gboolean no_splash,
anjuta_status_progress_tick (status, NULL, _("Loaded Session…"));
anjuta_status_disable_splash (status, TRUE);
/* Load template file */
if (template_uri != NULL)
{
GFile* file = g_file_new_for_uri (template_uri);
IAnjutaFileLoader *loader;
loader = anjuta_shell_get_interface (ANJUTA_SHELL (app),
IAnjutaFileLoader, NULL);
ianjuta_file_loader_load (loader, file, FALSE, NULL);
g_free (template_uri);
g_object_unref (file);
}
return app;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment