GFile * fetch_archive (const gchar *url, const gchar *sha, const gchar *module_name, GFile *destination, guint strip_components, GError **error) { g_autoptr(GFile) archive_file = NULL; g_autoptr(GFile) source_dir = NULL; g_autoptr(SoupURI) uri = NULL; g_autofree char *archive_name = NULL; GError *local_error = NULL; source_dir = g_file_get_child (destination, module_name); if (!g_file_make_directory_with_parents (source_dir, NULL, &local_error)) { if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { g_propagate_error (error, local_error); return NULL; } g_error_free (local_error); } uri = soup_uri_new (url); archive_name = g_path_get_basename (soup_uri_get_path (uri)); archive_file = g_file_get_child (source_dir, archive_name); if (!download_archive (uri, sha, archive_file, error)) return NULL; if (!extract_archive (source_dir, archive_file, strip_components, error)) return NULL; return g_steal_pointer (&source_dir); }
/* * At CREATE EXTENSION time we check if the extension is already available, * which is driven by the presence of its control file on disk. * * If the extension is not already available, we ask the repository server for * it, and unpack received binary archive to the right place. * * TODO: actually talk to the repository server. Current prototype version * directly uses the local archive cache. */ void download_and_unpack_archive(const char *extname) { PlatformData platform; char *control_filename = get_extension_control_filename(extname); char *archive_filename; /* * No cache, download again each time asked: any existing control file for * the extension could be one we left behind from a previous version of the * extension's archive. * * This also means that if an extension is already provided by the * operating system, by installing pginstall you give preference to * pginstall builds. */ current_platform(&platform); archive_filename = psprintf("%s/%s--%s--%s--%s--%s.tar.gz", pginstall_archive_dir, extname, PG_VERSION, escape_filename(platform.os_name), escape_filename(platform.os_version), escape_filename(platform.arch)); /* * The local repository might be added to directly by the pginstall build * client, and pginstall.serve_from_archive_dir allows to setup the * pginstall.archive_dir as a local authoritative source. * * Given that, we only download an archive file when * * 1. we have a pginstall.repository * 2. pginstall.serve_from_archive_dir is false * 3. pginstall.serve_from_archive_dir is true but we don't have the * needed file locally */ if (pginstall_repository != NULL && strcmp(pginstall_repository, "") != 0) { if (pginstall_serve_from_archive_dir && access(archive_filename, R_OK) == 0) { /* no download here. */ (void)0; } else { download_archive(archive_filename, extname, &platform); } } /* * Even if we didn't find any extension's archive file for our platform on * the repository server, it could be that the extension is available * locally either through the OS packages or maybe a local developer setup * (make install). * * In case when when extension control file still doesn't exists after * we've been communicating with the repository server, PostgreSQL will * issue its usual error message about a missing control file. */ if (access(archive_filename, R_OK) == 0) { extract(extname, archive_filename); /* now rewrite the control file to "relocate" the extension */ rewrite_control_file(extname, control_filename); } return; }