[darwinbuild-changes] [666] trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Dec 16 10:16:43 PST 2009


Revision: 666
          http://trac.macosforge.org/projects/darwinbuild/changeset/666
Author:   wsiegrist at apple.com
Date:     2009-12-16 10:16:43 -0800 (Wed, 16 Dec 2009)
Log Message:
-----------
Merge PR-6729491, PR-7431723, PR-7461534. Add CHANGES entries. Cleanup usage statement.

Modified Paths:
--------------
    trunk/CHANGES
    trunk/darwinup/Archive.cpp
    trunk/darwinup/Archive.h
    trunk/darwinup/Depot.cpp
    trunk/darwinup/Depot.h
    trunk/darwinup/Utils.cpp
    trunk/darwinup/Utils.h
    trunk/darwinup/main.cpp

Property Changed:
----------------
    trunk/
    trunk/darwinbuild/darwinbuild.in
    trunk/darwinbuild/darwinmaster.in
    trunk/darwinbuild/installXcode.in
    trunk/darwinbuild/packageRoots.in
    trunk/darwinbuild/thinPackages.in


Property changes on: trunk
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/PR-4841388:399-419
/branches/PR-6358021:442-443
/branches/PR-6392966:423-427
/branches/PR-6398060:433-434
/branches/PR-6493844:460-461
/branches/PR-6497694:466-468,471
/branches/PR-6634286:632-650
/branches/PR-6688645:479-490
/branches/PR-6722857:495-499
/branches/PR-7250612:635-650
/trunk:432-434
   + /branches/PR-4841388:399-419
/branches/PR-6358021:442-443
/branches/PR-6392966:423-427
/branches/PR-6398060:433-434
/branches/PR-6493844:460-461
/branches/PR-6497694:466-468,471
/branches/PR-6634286:632-650
/branches/PR-6688645:479-490
/branches/PR-6722857:495-499
/branches/PR-6729491:655-664
/branches/PR-7250612:635-650
/branches/PR-7431723:660-664
/branches/PR-7461534:650-664
/trunk:432-434

Modified: trunk/CHANGES
===================================================================
--- trunk/CHANGES	2009-12-16 16:10:12 UTC (rev 665)
+++ trunk/CHANGES	2009-12-16 18:16:43 UTC (rev 666)
@@ -1,6 +1,13 @@
 Darwin Build Scripts Change History
 -----------------------------------
 
+Release 13 [16-Dec-2009]
+	- darwinup: convert use of fork()/exec() to posix_spawn()
+	- darwinup: add Serial to archive list, allow use of serial, name, 
+	  and keywords to identify archives on the command line
+	- darwinup: support fetching archives via rsync and curl
+	- darwinup: support cpio, xar, zip and pax archives
+
 Release 12 [10-Dec-2009]
 	- darwinup: rollback installations that fail
 	- darwinup: add force (-f) option to allow potentially unsafe operations


Property changes on: trunk/darwinbuild/darwinbuild.in
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/PR-4841388/darwinbuild/darwinbuild:399-419
/branches/PR-6358021/darwinbuild/darwinbuild:442-443
/branches/PR-6392966/darwinbuild/darwinbuild:423-427
/branches/PR-6398060/darwinbuild/darwinbuild:433-434
/branches/PR-6493844/darwinbuild/darwinbuild.in:460-461
/branches/PR-6497694/darwinbuild/darwinbuild.in:466-468,471
/branches/PR-6634286/darwinbuild/darwinbuild.in:632-650
/branches/PR-6688645/darwinbuild/darwinbuild.in:479-490
/branches/PR-6722857/darwinbuild/darwinbuild.in:495-499
/branches/PR-7250612/darwinbuild/darwinbuild.in:635-650
/trunk/darwinbuild/darwinbuild:432-434
   + /branches/PR-4841388/darwinbuild/darwinbuild:399-419
/branches/PR-6358021/darwinbuild/darwinbuild:442-443
/branches/PR-6392966/darwinbuild/darwinbuild:423-427
/branches/PR-6398060/darwinbuild/darwinbuild:433-434
/branches/PR-6493844/darwinbuild/darwinbuild.in:460-461
/branches/PR-6497694/darwinbuild/darwinbuild.in:466-468,471
/branches/PR-6634286/darwinbuild/darwinbuild.in:632-650
/branches/PR-6688645/darwinbuild/darwinbuild.in:479-490
/branches/PR-6722857/darwinbuild/darwinbuild.in:495-499
/branches/PR-6729491/darwinbuild/darwinbuild.in:655-664
/branches/PR-7250612/darwinbuild/darwinbuild.in:635-650
/branches/PR-7431723/darwinbuild/darwinbuild.in:660-664
/branches/PR-7461534/darwinbuild/darwinbuild.in:650-664
/trunk/darwinbuild/darwinbuild:432-434


Property changes on: trunk/darwinbuild/darwinmaster.in
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/PR-4841388/darwinbuild/darwinmaster.sh:399-419
/branches/PR-6358021/darwinbuild/darwinmaster.sh:442-443
/branches/PR-6392966/darwinbuild/darwinmaster.sh:423-427
/branches/PR-6398060/darwinbuild/darwinmaster.sh:433-434
/branches/PR-6493844/darwinbuild/darwinmaster.sh.in:460-461
/branches/PR-6497694/darwinbuild/darwinmaster.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/darwinmaster.in:632-650
/branches/PR-6688645/darwinbuild/darwinmaster.sh.in:479-490
/branches/PR-6722857/darwinbuild/darwinmaster.sh.in:495-499
/branches/PR-7250612/darwinbuild/darwinmaster.in:635-650
/trunk/darwinbuild/darwinmaster.sh:432-434
   + /branches/PR-4841388/darwinbuild/darwinmaster.sh:399-419
/branches/PR-6358021/darwinbuild/darwinmaster.sh:442-443
/branches/PR-6392966/darwinbuild/darwinmaster.sh:423-427
/branches/PR-6398060/darwinbuild/darwinmaster.sh:433-434
/branches/PR-6493844/darwinbuild/darwinmaster.sh.in:460-461
/branches/PR-6497694/darwinbuild/darwinmaster.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/darwinmaster.in:632-650
/branches/PR-6688645/darwinbuild/darwinmaster.sh.in:479-490
/branches/PR-6722857/darwinbuild/darwinmaster.sh.in:495-499
/branches/PR-6729491/darwinbuild/darwinmaster.in:655-664
/branches/PR-7250612/darwinbuild/darwinmaster.in:635-650
/branches/PR-7431723/darwinbuild/darwinmaster.in:660-664
/branches/PR-7461534/darwinbuild/darwinmaster.in:650-664
/trunk/darwinbuild/darwinmaster.sh:432-434


Property changes on: trunk/darwinbuild/installXcode.in
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/PR-4841388/darwinbuild/installXcode:399-419
/branches/PR-6358021/darwinbuild/installXcode:442-443
/branches/PR-6392966/darwinbuild/installXcode:423-427
/branches/PR-6398060/darwinbuild/installXcode:433-434
/branches/PR-6493844/darwinbuild/installXcode.in:460-461
/branches/PR-6497694/darwinbuild/installXcode.in:466-468,471
/branches/PR-6634286/darwinbuild/installXcode.in:632-650
/branches/PR-6688645/darwinbuild/installXcode.in:479-490
/branches/PR-6722857/darwinbuild/installXcode.in:495-499
/branches/PR-7250612/darwinbuild/installXcode.in:635-650
/trunk/darwinbuild/installXcode:432-434
   + /branches/PR-4841388/darwinbuild/installXcode:399-419
/branches/PR-6358021/darwinbuild/installXcode:442-443
/branches/PR-6392966/darwinbuild/installXcode:423-427
/branches/PR-6398060/darwinbuild/installXcode:433-434
/branches/PR-6493844/darwinbuild/installXcode.in:460-461
/branches/PR-6497694/darwinbuild/installXcode.in:466-468,471
/branches/PR-6634286/darwinbuild/installXcode.in:632-650
/branches/PR-6688645/darwinbuild/installXcode.in:479-490
/branches/PR-6722857/darwinbuild/installXcode.in:495-499
/branches/PR-6729491/darwinbuild/installXcode.in:655-664
/branches/PR-7250612/darwinbuild/installXcode.in:635-650
/branches/PR-7431723/darwinbuild/installXcode.in:660-664
/branches/PR-7461534/darwinbuild/installXcode.in:650-664
/trunk/darwinbuild/installXcode:432-434


Property changes on: trunk/darwinbuild/packageRoots.in
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/PR-4841388/darwinbuild/packageRoots.sh:399-419
/branches/PR-6358021/darwinbuild/packageRoots.sh:442-443
/branches/PR-6392966/darwinbuild/packageRoots.sh:423-427
/branches/PR-6398060/darwinbuild/packageRoots.sh:433-434
/branches/PR-6493844/darwinbuild/packageRoots.sh.in:460-461
/branches/PR-6497694/darwinbuild/packageRoots.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/packageRoots.in:632-650
/branches/PR-6688645/darwinbuild/packageRoots.sh.in:479-490
/branches/PR-6722857/darwinbuild/packageRoots.sh.in:495-499
/branches/PR-7250612/darwinbuild/packageRoots.in:635-650
/trunk/darwinbuild/packageRoots.sh:432-434
   + /branches/PR-4841388/darwinbuild/packageRoots.sh:399-419
/branches/PR-6358021/darwinbuild/packageRoots.sh:442-443
/branches/PR-6392966/darwinbuild/packageRoots.sh:423-427
/branches/PR-6398060/darwinbuild/packageRoots.sh:433-434
/branches/PR-6493844/darwinbuild/packageRoots.sh.in:460-461
/branches/PR-6497694/darwinbuild/packageRoots.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/packageRoots.in:632-650
/branches/PR-6688645/darwinbuild/packageRoots.sh.in:479-490
/branches/PR-6722857/darwinbuild/packageRoots.sh.in:495-499
/branches/PR-6729491/darwinbuild/packageRoots.in:655-664
/branches/PR-7250612/darwinbuild/packageRoots.in:635-650
/branches/PR-7431723/darwinbuild/packageRoots.in:660-664
/branches/PR-7461534/darwinbuild/packageRoots.in:650-664
/trunk/darwinbuild/packageRoots.sh:432-434


Property changes on: trunk/darwinbuild/thinPackages.in
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/PR-4841388/darwinbuild/thinPackages.sh:399-419
/branches/PR-6358021/darwinbuild/thinPackages.sh:442-443
/branches/PR-6392966/darwinbuild/thinPackages.sh:423-427
/branches/PR-6398060/darwinbuild/thinPackages.sh:433-434
/branches/PR-6493844/darwinbuild/thinPackages.sh.in:460-461
/branches/PR-6497694/darwinbuild/thinPackages.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/thinPackages.in:632-650
/branches/PR-6688645/darwinbuild/thinPackages.sh.in:479-490
/branches/PR-6722857/darwinbuild/thinPackages.sh.in:495-499
/branches/PR-7250612/darwinbuild/thinPackages.in:635-650
/trunk/darwinbuild/thinPackages.sh:432-434
   + /branches/PR-4841388/darwinbuild/thinPackages.sh:399-419
/branches/PR-6358021/darwinbuild/thinPackages.sh:442-443
/branches/PR-6392966/darwinbuild/thinPackages.sh:423-427
/branches/PR-6398060/darwinbuild/thinPackages.sh:433-434
/branches/PR-6493844/darwinbuild/thinPackages.sh.in:460-461
/branches/PR-6497694/darwinbuild/thinPackages.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/thinPackages.in:632-650
/branches/PR-6688645/darwinbuild/thinPackages.sh.in:479-490
/branches/PR-6722857/darwinbuild/thinPackages.sh.in:495-499
/branches/PR-6729491/darwinbuild/thinPackages.in:655-664
/branches/PR-7250612/darwinbuild/thinPackages.in:635-650
/branches/PR-7431723/darwinbuild/thinPackages.in:660-664
/branches/PR-7461534/darwinbuild/thinPackages.in:650-664
/trunk/darwinbuild/thinPackages.sh:432-434

Modified: trunk/darwinup/Archive.cpp
===================================================================
--- trunk/darwinup/Archive.cpp	2009-12-16 16:10:12 UTC (rev 665)
+++ trunk/darwinup/Archive.cpp	2009-12-16 18:16:43 UTC (rev 666)
@@ -174,6 +174,31 @@
 }
 
 
+DittoXArchive::DittoXArchive(const char* path) : Archive(path) {}
+
+int DittoXArchive::extract(const char* destdir) {
+	const char* args[] = {
+		"/usr/bin/ditto",
+		"-x", m_path,
+		destdir,
+		NULL
+	};
+	return exec_with_args(args);
+}
+
+CpioArchive::CpioArchive(const char* path) : DittoXArchive(path) {}
+
+CpioGZArchive::CpioGZArchive(const char* path) : DittoXArchive(path) {}
+
+CpioBZ2Archive::CpioBZ2Archive(const char* path) : DittoXArchive(path) {}
+
+PaxArchive::PaxArchive(const char* path) : DittoXArchive(path) {}
+
+PaxGZArchive::PaxGZArchive(const char* path) : DittoXArchive(path) {}
+
+PaxBZ2Archive::PaxBZ2Archive(const char* path) : DittoXArchive(path) {}
+
+
 TarArchive::TarArchive(const char* path) : Archive(path) {}
 
 int TarArchive::extract(const char* destdir) {
@@ -213,26 +238,92 @@
 }
 
 
-Archive* ArchiveFactory(const char* path) {
+XarArchive::XarArchive(const char* path) : Archive(path) {}
+
+int XarArchive::extract(const char* destdir) {
+	const char* args[] = {
+		"/usr/bin/xar",
+		"-xf", m_path,
+		"-C", destdir,
+		NULL
+	};
+	return exec_with_args(args);
+}
+
+
+ZipArchive::ZipArchive(const char* path) : Archive(path) {}
+
+int ZipArchive::extract(const char* destdir) {
+	const char* args[] = {
+		"/usr/bin/ditto",
+		"-xk", m_path,
+		destdir,
+		NULL
+	};
+	return exec_with_args(args);
+}
+
+
+Archive* ArchiveFactory(const char* path, const char* tmppath) {
 	Archive* archive = NULL;
 
+	// actual path to archive
+	char* actpath = NULL; 
+	
+	// fetch remote archives if needed
+	if (is_url_path(path)) {
+		actpath = fetch_url(path, tmppath);
+		if (!actpath) {
+			fprintf(stderr, "Error: could not fetch remote URL: %s \n", path);
+			return NULL;
+		}
+	} else if (is_userhost_path(path)) {
+		actpath = fetch_userhost(path, tmppath);
+		if (!actpath) {
+			fprintf(stderr, "Error: could not fetch remote file from: %s \n", path);
+			return NULL;
+		}
+	} else {
+		actpath = (char *)path;
+	}
+
+	
 	// make sure the archive exists
 	struct stat sb;
-	int res = stat(path, &sb);
+	int res = stat(actpath, &sb);
 	if (res == -1 && errno == ENOENT) {
 		return NULL;
 	}
-
-	if (is_directory(path)) {
-		archive = new DittoArchive(path);
-	} else if (has_suffix(path, ".tar")) {
-		archive = new TarArchive(path);
-	} else if (has_suffix(path, ".tar.gz") || has_suffix(path, ".tgz")) {
-		archive = new TarGZArchive(path);
-	} else if (has_suffix(path, ".tar.bz2") || has_suffix(path, ".tbz2")) {
-		archive = new TarBZ2Archive(path);
+	
+	// use file extension to guess archive format
+	if (is_directory(actpath)) {
+		archive = new DittoArchive(actpath);
+	} else if (has_suffix(actpath, ".cpio")) {
+		archive = new CpioArchive(actpath);
+	} else if (has_suffix(actpath, ".cpio.gz") || has_suffix(actpath, ".cpgz")) {
+		archive = new CpioGZArchive(actpath);
+	} else if (has_suffix(actpath, ".cpio.bz2") || has_suffix(actpath, ".cpbz2")) {
+		archive = new CpioBZ2Archive(actpath);
+	} else if (has_suffix(actpath, ".pax")) {
+		archive = new PaxArchive(actpath);
+	} else if (has_suffix(actpath, ".pax.gz") || has_suffix(actpath, ".pgz")) {
+		archive = new PaxGZArchive(actpath);
+	} else if (has_suffix(actpath, ".pax.bz2") || has_suffix(actpath, ".pbz2")) {
+		archive = new PaxBZ2Archive(actpath);		
+	} else if (has_suffix(actpath, ".tar")) {
+		archive = new TarArchive(actpath);
+	} else if (has_suffix(actpath, ".tar.gz") || has_suffix(actpath, ".tgz")) {
+		archive = new TarGZArchive(actpath);
+	} else if (has_suffix(actpath, ".tar.bz2") || has_suffix(actpath, ".tbz2")) {
+		archive = new TarBZ2Archive(actpath);		
+	} else if (has_suffix(actpath, ".xar")) {
+		archive = new XarArchive(actpath);
+	} else if (has_suffix(actpath, ".zip")) {
+		archive = new ZipArchive(actpath);
 	} else {
 		fprintf(stderr, "Error: unknown archive type: %s\n", path);
 	}
+	
+	if (actpath && actpath != path) free(actpath);
 	return archive;
 }

Modified: trunk/darwinup/Archive.h
===================================================================
--- trunk/darwinup/Archive.h	2009-12-16 16:10:12 UTC (rev 665)
+++ trunk/darwinup/Archive.h	2009-12-16 18:16:43 UTC (rev 666)
@@ -57,10 +57,12 @@
 //  ArchiveFactory exists to return the correct
 //  concrete subclass for a given archive to be
 //  installed.  Currently this is determined
-//  by the file's suffix.
+//  by the file's suffix. The tmppath parameter
+//  is the path where files can be stored during
+//  processing, such as fetching remote archives. 
 ////
 
-Archive* ArchiveFactory(const char* path);
+Archive* ArchiveFactory(const char* path, const char* tmppath);
 
 struct Archive {
 	Archive(const char* path);
@@ -120,7 +122,7 @@
 
 	// Constructor for subclasses and Depot to use when unserializing an archive from the database.
 	Archive(uint64_t serial, uuid_t uuid, const char* name, const char* path, uint64_t info, time_t date_installed);
-
+	
 	uint64_t	m_serial;
 	uuid_t		m_uuid;
 	char*		m_name;
@@ -158,27 +160,96 @@
 
 
 ////
-//  PkgArchive
+//  DittoXArchive
 //
-//  Corresponds to the Mac OS X installer's .pkg bundle format.
-//  Installs the archive using the pax(1) command line tool.
-//  NOTE: this does not make any attempt to perform any of the
-//  volume checks or run any preflight or postflight actions.
+//  Handles any file that `ditto -x` can handle. Intended to be the parent
+//  of suffix-specific archive objects. 
 ////
-struct PkgArchive : public Archive {
-	PkgArchive(const char* path);
+struct DittoXArchive : public Archive {
+	DittoXArchive(const char* path);
 	virtual int extract(const char* destdir);
 };
 
+
 ////
+//  CpioArchive
+//
+//  Corresponds to the cpio(1) file format.  
+//  This installs archives using the ditto(1) command line tool with
+//  the -x option.
+////
+struct CpioArchive : public DittoXArchive {
+	CpioArchive(const char* path);
+};
+
+////
+//  CpioGZArchive
+//
+//  Corresponds to the cpio(1) file format, compressed with gzip(1).
+//  This installs archives using the ditto(1) command line tool with
+//  the -x option.
+////
+struct CpioGZArchive : public DittoXArchive {
+	CpioGZArchive(const char* path);
+};
+
+////
+//  CpioBZ2Archive
+//
+//  Corresponds to the cpio(1) file format, compressed with bzip2(1).
+//  This installs archives using the ditto(1) command line tool with
+//  the -x option.
+////
+struct CpioBZ2Archive : public DittoXArchive {
+	CpioBZ2Archive(const char* path);
+};
+
+
+////
+//  PaxArchive
+//
+//  Corresponds to the pax(1) file format.  
+//  This installs archives using the ditto(1) command line tool with
+//  the -x option.
+////
+struct PaxArchive : public DittoXArchive {
+	PaxArchive(const char* path);
+};
+
+
+////
+//  PaxGZArchive
+//
+//  Corresponds to the pax(1) file format, compressed with gzip(1).
+//  This installs archives using the ditto(1) command line tool with
+//  the -x option.
+////
+struct PaxGZArchive : public DittoXArchive {
+	PaxGZArchive(const char* path);
+};
+
+
+////
+//  PaxBZ2Archive
+//
+//  Corresponds to the pax(1) file format, compressed with bzip2(1).
+//  This installs archives using the ditto(1) command line tool with
+//  the -x option.
+////
+struct PaxBZ2Archive : public DittoXArchive {
+	PaxBZ2Archive(const char* path);
+};
+
+
+////
 //  TarArchive
 //
 //  Corresponds to the tar(1) file format.  This handles uncompressed tar
 //  archives by using the tar(1) command line tool.
 ////
 struct TarArchive : public Archive {
-	TarArchive(const char* path);
-	virtual int extract(const char* destdir);
+        TarArchive(const char* path);
+        virtual int extract(const char* destdir);
 };
 
 
@@ -190,8 +261,8 @@
 //  the -z option.
 ////
 struct TarGZArchive : public Archive {
-	TarGZArchive(const char* path);
-	virtual int extract(const char* destdir);
+        TarGZArchive(const char* path);
+        virtual int extract(const char* destdir);
 };
 
 
@@ -203,6 +274,30 @@
 //  the -j option.
 ////
 struct TarBZ2Archive : public Archive {
-	TarBZ2Archive(const char* path);
+        TarBZ2Archive(const char* path);
+        virtual int extract(const char* destdir);
+};
+
+
+////
+//  XarArchive
+//
+//  Corresponds to the xar(1) file format.  This handles uncompressed cpio
+//  archives by using the xar(1) command line tool.
+////
+struct XarArchive : public Archive {
+	XarArchive(const char* path);
 	virtual int extract(const char* destdir);
 };
+
+
+////
+//  ZipArchive
+//
+//  Corresponds to a zip archive. We use the -k option to ditto(1)
+//  to handle it. 
+////
+struct ZipArchive : public Archive {
+	ZipArchive(const char* path);
+	virtual int extract(const char* destdir);
+};

Modified: trunk/darwinup/Depot.cpp
===================================================================
--- trunk/darwinup/Depot.cpp	2009-12-16 16:10:12 UTC (rev 665)
+++ trunk/darwinup/Depot.cpp	2009-12-16 18:16:43 UTC (rev 666)
@@ -55,6 +55,7 @@
 	m_depot_path = NULL;
 	m_database_path = NULL;
 	m_archives_path = NULL;
+	m_downloads_path = NULL;
 	m_db = NULL;
 	m_lock_fd = -1;
 	m_is_locked = 0;
@@ -70,6 +71,7 @@
 	join_path(&m_depot_path, m_prefix, "/.DarwinDepot");
 	join_path(&m_database_path, m_depot_path, "/Database-V100");
 	join_path(&m_archives_path, m_depot_path, "/Archives");
+	join_path(&m_downloads_path, m_depot_path, "/Downloads");
 }
 
 Depot::~Depot() {
@@ -79,9 +81,11 @@
 	if (m_depot_path)	free(m_depot_path);
 	if (m_database_path)	free(m_database_path);
 	if (m_archives_path)	free(m_archives_path);
+	if (m_downloads_path)	free(m_downloads_path);
 }
 
 const char*	Depot::archives_path()		{ return m_archives_path; }
+const char*	Depot::downloads_path()		{ return m_downloads_path; }
 const char*     Depot::prefix()                 { return m_prefix; }
 
 // Initialize the depot storage on disk
@@ -89,7 +93,7 @@
 	int res = 0;
 	
 	// initialization requires all these paths to be set
-	if (!(m_prefix && m_depot_path && m_database_path && m_archives_path)) {
+	if (!(m_prefix && m_depot_path && m_database_path && m_archives_path && m_downloads_path)) {
 		return -1;
 	}
 	
@@ -104,6 +108,12 @@
 		return res;
 	}
 	
+	res = mkdir(m_downloads_path, m_depot_mode);
+	if (res && errno != EEXIST) {
+		perror(m_downloads_path);
+		return res;
+	}
+
 	res = this->lock(LOCK_SH);
 	if (res) return res;
 	m_is_locked = 1;
@@ -192,57 +202,181 @@
 	return archive;
 }
 
-Archive* Depot::archive(const char* uuid) {
-	uuid_t uu;
-	if (uuid_parse(uuid, uu) == 0) {
-		return Depot::archive(uu);
+// Unserialize an archive from the database.
+// Find the last archive installed with this name
+Archive* Depot::archive(archive_name_t name) {
+	int res = 0;
+	Archive* archive = NULL;
+	static sqlite3_stmt* stmt = NULL;
+	if (stmt == NULL && m_db) {
+		const char* query = "SELECT serial, uuid, info, date_added FROM archives WHERE name=? ORDER BY date_added DESC LIMIT 1";
+		res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
+		if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
+	}
+	if (stmt && res == 0) {
+		res = sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC);
+		if (res == 0) res = sqlite3_step(stmt);
+		if (res == SQLITE_ROW) {
+			uuid_t uuid;
+			const void* blob = sqlite3_column_blob(stmt, 1);
+			int blobsize = sqlite3_column_bytes(stmt, 1);
+			if (blobsize > 0) {
+				assert(blobsize == sizeof(uuid_t));
+				memcpy(uuid, blob, sizeof(uuid_t));
+			} else {
+				uuid_clear(uuid);
+			}
+			uint64_t serial = sqlite3_column_int64(stmt, 0);
+			uint64_t info = sqlite3_column_int64(stmt, 2);
+			time_t date_added = sqlite3_column_int(stmt, 3);
+			archive = new Archive(serial, uuid, (const char*)name, NULL, info, date_added);
+		}
+		sqlite3_reset(stmt);
+	}
+	return archive;
+}
+
+Archive* Depot::archive(archive_keyword_t keyword) {
+	int res = 0;
+	Archive* archive = NULL;
+	static sqlite3_stmt* stmt = NULL;
+	const char* query = NULL;
+	if (stmt == NULL && m_db) {
+		if (keyword == DEPOT_ARCHIVE_NEWEST) {
+			query = "SELECT serial FROM archives WHERE name != '<Rollback>' ORDER BY date_added DESC LIMIT 1";
+		} else if (keyword == DEPOT_ARCHIVE_OLDEST) {
+			query = "SELECT serial FROM archives WHERE name != '<Rollback>' ORDER BY date_added ASC LIMIT 1";
+		} else {
+			fprintf(stderr, "Error: unknown archive keyword.\n");
+			res = -1;
+		}
+		if (res == 0) res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
+		if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
+	}
+	if (stmt && res == 0) {
+		res = sqlite3_step(stmt);
+		if (res == SQLITE_ROW) {
+			uint64_t serial = sqlite3_column_int64(stmt, 0);
+			archive = Depot::archive(serial);
+		}
+		sqlite3_reset(stmt);
+	}
+	return archive;	
+}
+
+// create a new Archive from a database row
+Archive* Depot::archive(sqlite3_stmt* stmt) {
+	uuid_t uuid;
+	uint64_t serial = sqlite3_column_int64(stmt, 0);
+	const void* blob = sqlite3_column_blob(stmt, 1);
+	int blobsize = sqlite3_column_bytes(stmt, 1);
+	const unsigned char* name = sqlite3_column_text(stmt, 2);
+	uint64_t info = sqlite3_column_int64(stmt, 3);
+	time_t date_added = sqlite3_column_int(stmt, 4);
+	if (blobsize > 0) {
+		assert(blobsize == sizeof(uuid_t));
+		memcpy(uuid, blob, sizeof(uuid_t));
 	} else {
-		return NULL;
+		uuid_clear(uuid);
 	}
+	return new Archive(serial, uuid, (const char*)name, NULL, info, date_added);	
 }
 
-int Depot::iterate_archives(ArchiveIteratorFunc func, void* context) {
+
+// Return Archive from database matching arg, which is one of:
+//
+//   uuid (ex: 22969F32-9C4F-4370-82C8-DD3609736D8D)
+//   serial (ex: 12)
+//   name  (ex root.tar.gz)
+//   keyword (either "newest" for the most recent root installed
+//            or     "oldest" for the oldest installed root)
+//   
+Archive* Depot::get_archive(const char* arg) {
+	uuid_t uuid;
+	uint64_t serial; 
+	if (uuid_parse(arg, uuid) == 0) {
+		return Depot::archive(uuid);
+	}
+	serial = strtoull(arg, NULL, 0);
+	if (serial) {
+		return Depot::archive(serial);
+	}
+	if (strncasecmp("oldest", arg, 6) == 0) {
+		IF_DEBUG("looking for oldest\n");
+		return Depot::archive(DEPOT_ARCHIVE_OLDEST);
+	}
+	if (strncasecmp("newest", arg, 6) == 0) {
+		IF_DEBUG("looking for newest\n");
+		return Depot::archive(DEPOT_ARCHIVE_NEWEST);
+	}
+	return Depot::archive((archive_name_t)arg);
+}
+
+Archive** Depot::get_all_archives(size_t* count) {
+	extern uint32_t verbosity;
 	int res = 0;
+	*count = this->count_archives();
+	//fprintf(stderr, "DEBUG: get_all_archives got count = %d \n", (int)*count);
+	Archive** list = (Archive**)malloc(*count * sizeof(Archive*));
 	static sqlite3_stmt* stmt = NULL;
 	if (stmt == NULL && m_db) {
-		const char* query = "SELECT serial, uuid, name, info, date_added FROM archives ORDER BY serial DESC";
+		const char* query = "SELECT serial, uuid, name, info, date_added FROM archives WHERE name != '<Rollback>' ORDER BY serial DESC";
+		if (verbosity & VERBOSE_DEBUG) {
+			query = "SELECT serial, uuid, name, info, date_added FROM archives ORDER BY serial DESC";
+		}
 		res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
 		if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
 	}
 	if (stmt && res == 0) {
-		while (res == 0) {
+		size_t i = 0;
+		while (res != SQLITE_DONE) {
 			res = sqlite3_step(stmt);
 			if (res == SQLITE_ROW) {
-				res = 0;
-				uuid_t uuid;
-				uint64_t serial = sqlite3_column_int64(stmt, 0);
-				const void* blob = sqlite3_column_blob(stmt, 1);
-				int blobsize = sqlite3_column_bytes(stmt, 1);
-				const unsigned char* name = sqlite3_column_text(stmt, 2);
-				uint64_t info = sqlite3_column_int64(stmt, 3);
-				time_t date_added = sqlite3_column_int(stmt, 4);
-				if (blobsize > 0) {
-					assert(blobsize == sizeof(uuid_t));
-					memcpy(uuid, blob, sizeof(uuid_t));
-				} else {
-					uuid_clear(uuid);
-				}
-				Archive* archive = new Archive(serial, uuid, (const char*)name, NULL, info, date_added);
-				if (archive) {
-					res = func(archive, context);
-					delete archive;
-				} else {
-					fprintf(stderr, "%s:%d: new Archive returned NULL\n", __FILE__, __LINE__);
-					res = -1;
-					break;
-				}
-			} else if (res == SQLITE_DONE) {
-				res = 0;
-				break;
-			}
+				//fprintf(stderr, "DEBUG: making %d-th archive \n", (int)i);
+				list[i++] = this->archive(stmt);
+				//fprintf(stderr, "DEBUG: archive = %p \n", list[i-1]);
+			} 
 		}
 		sqlite3_reset(stmt);
 	}
+	return list;	
+}
+
+size_t Depot::count_archives() {
+	extern uint32_t verbosity;
+	int res = 0;
+	size_t count = 0;
+	static sqlite3_stmt* stmt = NULL;
+	if (stmt == NULL && m_db) {
+		const char* query = "SELECT count(*) FROM archives WHERE name != '<Rollback>'";
+		if (verbosity & VERBOSE_DEBUG) {
+			query = "SELECT count(*) FROM archives";
+		}
+		res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
+		if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
+	}
+	if (stmt && res == 0) {
+		res = sqlite3_step(stmt);
+		if (res == SQLITE_ROW) {
+			count = sqlite3_column_int64(stmt, 0);
+		}
+		sqlite3_reset(stmt);
+	}
+	return count;
+}
+
+int Depot::iterate_archives(ArchiveIteratorFunc func, void* context) {
+	int res = 0;
+	size_t count = 0;
+	Archive** list = this->get_all_archives(&count);
+	//fprintf(stderr, "DEBUG: iterate got: %p %d \n", *list, (int)count);
+	for (size_t i = 0; i < count; i++) {
+		//fprintf(stderr, "DEBUG: iterating on i = %d list[i] = %p \n", (int)i, list[i]);
+		if (list[i]) {
+			res = func(list[i], context);
+			delete list[i];
+		}
+	}
 	return res;
 }
 
@@ -736,12 +870,18 @@
 }
 
 int Depot::uninstall(Archive* archive) {
+	extern uint32_t verbosity;
 	int res = 0;
 
 	assert(archive != NULL);
 	uint64_t serial = archive->serial();
 
 	if (INFO_TEST(archive->info(), ARCHIVE_INFO_ROLLBACK)) {
+		// if in debug mode, get_all_archives returns rollbacks too, so just ignore
+		if (verbosity & VERBOSE_DEBUG) {
+			fprintf(stderr, "[uninstall] skipping uninstall since archive is a rollback.\n");
+			return 0;
+		}
 		fprintf(stderr, "%s:%d: cannot uninstall a rollback archive.\n", __FILE__, __LINE__);
 		return -1;
 	}
@@ -806,12 +946,18 @@
 
 int Depot::verify(Archive* archive) {
 	int res = 0;
+	fprintf(stdout, "%-6s %-36s  %-23s  %s\n", "Serial", "UUID", "Date Installed", "Name");
+	fprintf(stdout, "====== ====================================  =======================  =================\n");
+	list_archive(archive, stdout);	
+	fprintf(stdout, "=======================================================================================\n");
 	if (res == 0) res = this->iterate_files(archive, &Depot::verify_file, NULL);
+	fprintf(stdout, "=======================================================================================\n\n");
 	return res;
 }
 
-int Depot::list_archive(Archive* archive, void* context) {
-	extern uint32_t verbosity;
+int Depot::list_archive(Archive* archive, void* context) {	
+	uint64_t serial = archive->serial();
+	
 	char uuid[37];
 	uuid_unparse_upper(archive->uuid(), uuid);
 
@@ -821,18 +967,15 @@
 	localtime_r(&seconds, &local);
 	strftime(date, sizeof(date), "%F %T %Z", &local);
 
-	if (!INFO_TEST(archive->info(), ARCHIVE_INFO_ROLLBACK) ||
-	    (verbosity & VERBOSE_DEBUG)) {
-		fprintf((FILE*)context, "%-36s  %-23s  %s\n", uuid, date, archive->name());
-	}
+	fprintf((FILE*)context, "%-6llu %-36s  %-23s  %s\n", serial, uuid, date, archive->name());
 	
 	return 0;
 }
 
 int Depot::list() {
 	int res = 0;
-	fprintf(stdout, "%-36s  %-23s  %s\n", "UUID", "Date Installed", "Name");
-	fprintf(stdout, "====================================  =======================  =================\n");
+	fprintf(stdout, "%-6s %-36s  %-23s  %s\n", "Serial", "UUID", "Date Installed", "Name");
+	fprintf(stdout, "====== ====================================  =======================  =================\n");
 	if (res == 0) res = this->iterate_archives(&Depot::list_archive, stdout);
 	return res;
 }
@@ -846,11 +989,12 @@
 
 int Depot::files(Archive* archive) {
 	int res = 0;
-	fprintf(stdout, "%-36s  %-23s  %s\n", "UUID", "Date Installed", "Name");
-	fprintf(stdout, "====================================  =======================  =================\n");
+	fprintf(stdout, "%-6s %-36s  %-23s  %s\n", "Serial", "UUID", "Date Installed", "Name");
+	fprintf(stdout, "====== ====================================  =======================  =================\n");
 	list_archive(archive, stdout);
-	fprintf(stdout, "================================================================================\n");
+	fprintf(stdout, "=======================================================================================\n");
 	if (res == 0) res = this->iterate_files(archive, &Depot::print_file, stdout);
+	fprintf(stdout, "=======================================================================================\n\n");
 	return res;
 }
 
@@ -858,9 +1002,9 @@
 	Depot* depot = (Depot*)context;
 	int res = 0;
 	list_archive(archive, stdout);
-	fprintf(stdout, "================================================================================\n");
+	fprintf(stdout, "=======================================================================================\n");
 	if (res == 0) res = depot->iterate_files(archive, &Depot::print_file, stdout);
-	fprintf(stdout, "================================================================================\n\n\n");
+	fprintf(stdout, "=======================================================================================\n\n");
 	return res;
 }
 
@@ -868,8 +1012,8 @@
 	extern uint32_t verbosity;
 	verbosity = 0xFFFFFFFF; // dump is intrinsically a debug command
 	int res = 0;
-	fprintf(stdout, "%-36s  %-23s  %s\n", "UUID", "Date Installed", "Name");
-	fprintf(stdout, "====================================  =======================  =================\n");
+	fprintf(stdout, "%-6s %-36s  %-23s  %s\n", "Serial", "UUID", "Date Installed", "Name");
+	fprintf(stdout, "====== ====================================  =======================  =================\n");
 	if (res == 0) res = this->iterate_archives(&Depot::dump_archive, this);
 	return res;
 }
@@ -1138,7 +1282,63 @@
 	return res;
 }
 
+// helper to dispatch the actual command for process_archive()
+int Depot::dispatch_command(Archive* archive, const char* command) {
+	int res = 0;
 
+	if (strncasecmp((char*)command, "files", 5) == 0) {
+		res = this->files(archive);
+	} else if (strncasecmp((char*)command, "uninstall", 9) == 0) {
+		res = this->uninstall(archive);
+	} else if (strncasecmp((char*)command, "verify", 6) == 0) {
+		res = this->verify(archive);
+	} else {
+		fprintf(stderr, "Error: unknown command given to dispatch_command.\n");
+	}
+	if (res != 0) {
+		fprintf(stderr, "An error occurred.\n");
+	}
+	return res;
+}
+
+// perform a command on an archive specification
+int Depot::process_archive(const char* command, const char* arg) {
+	extern uint32_t verbosity;
+	int res = 0;
+	size_t count = 0;
+	Archive** list = NULL;
+	
+	if (strncasecmp(arg, "all", 3) == 0) {
+		list = this->get_all_archives(&count);
+	} else {
+		// make a list of 1 Archive
+		list = (Archive**)malloc(sizeof(Archive*));
+		list[0] = this->get_archive(arg);
+		count = 1;
+	}
+	
+	//fprintf(stderr, "DEBUG: count = %d \n", (int)count);
+	
+	for (size_t i = 0; i < count; i++) {
+		//fprintf(stderr, "DEBUG: i = %d \n", (int)i);
+		if (!list[i]) {
+			fprintf(stderr, "Archive not found: %s\n", arg);
+			return -1;
+		}
+		if (verbosity & VERBOSE_DEBUG) {
+			char uuid[37];
+			uuid_unparse_upper(list[i]->uuid(), uuid);
+			fprintf(stderr, "Found archive: %s\n", uuid);
+		}
+		//fprintf(stderr, "DEBUG: dispatching %p %s \n", list[i], command);
+		res = this->dispatch_command(list[i], command);
+		delete list[i];
+	} 
+	free(list);
+	return res;
+}
+
+
 #define __SQL(callback, context, fmt) \
 	va_list args; \
 	char* errmsg; \

Modified: trunk/darwinup/Depot.h
===================================================================
--- trunk/darwinup/Depot.h	2009-12-16 16:10:12 UTC (rev 665)
+++ trunk/darwinup/Depot.h	2009-12-16 18:16:43 UTC (rev 666)
@@ -40,6 +40,13 @@
 typedef int (*ArchiveIteratorFunc)(Archive* archive, void* context);
 typedef int (*FileIteratorFunc)(File* file, void* context);
 
+typedef char* archive_name_t;
+
+enum archive_keyword_t {
+		DEPOT_ARCHIVE_NEWEST,
+		DEPOT_ARCHIVE_OLDEST
+};
+
 struct Depot {
 	Depot();
 	Depot(const char* prefix);
@@ -49,18 +56,26 @@
 	int initialize();
 	int is_initialized();
 	
-        const char*     prefix();
+	const char* prefix();
 	const char*	database_path();
 	const char*	archives_path();
+	const char*	downloads_path();
 
 	virtual int	begin_transaction();
 	virtual int	commit_transaction();
 	virtual int	rollback_transaction();
 
-	Archive*	archive(uint64_t serial);
-	Archive*	archive(uuid_t uuid);
-	Archive*	archive(const char* uuid);
+	Archive* archive(uint64_t serial);
+	Archive* archive(uuid_t uuid);
+	Archive* archive(archive_name_t name);
+	Archive* archive(archive_keyword_t keyword);
+	Archive* archive(sqlite3_stmt* stmt);
+	Archive* get_archive(const char* arg);
 
+	// returns a list of Archive*. Caller must free the list. 
+	Archive** get_all_archives(size_t *count);
+	size_t count_archives();
+	
 	int dump();
 	static int dump_archive(Archive* archive, void* context);
 	
@@ -83,8 +98,13 @@
 	int iterate_files(Archive* archive, FileIteratorFunc func, void* context);
 	int iterate_archives(ArchiveIteratorFunc func, void* context);
 
-        // test if the depot is currently locked 
-        int is_locked();
+	// processes an archive according to command
+	//  arg is an archive identifier, such as serial or uuid
+	int dispatch_command(Archive* archive, const char* command);
+	int process_archive(const char* command, const char* arg);
+	
+	// test if the depot is currently locked 
+	int is_locked();
 
 	protected:
 
@@ -114,7 +134,7 @@
 	
 	// Removes all archive entries which have no corresponding files entries.
 	int		prune_archives();
-
+	
 	File*		file_superseded_by(File* file);
 	File*		file_preceded_by(File* file);
 	File*		file_star_eded_by(File* file, sqlite3_stmt* stmt);
@@ -130,6 +150,7 @@
 	char*		m_depot_path;
 	char*		m_database_path;
 	char*		m_archives_path;
+	char*		m_downloads_path;
 	int		m_lock_fd;
         int             m_is_locked;
 };

Modified: trunk/darwinup/Utils.cpp
===================================================================
--- trunk/darwinup/Utils.cpp	2009-12-16 16:10:12 UTC (rev 665)
+++ trunk/darwinup/Utils.cpp	2009-12-16 18:16:43 UTC (rev 666)
@@ -33,11 +33,13 @@
 #include "Utils.h"
 #include <assert.h>
 #include <errno.h>
+#include <libgen.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <spawn.h>
 #include <sys/stat.h>
 
 extern char** environ;
@@ -122,6 +124,23 @@
 	return (res == 0 && S_ISREG(sb.st_mode));
 }
 
+int is_url_path(const char* path) {
+	if (strncmp("http://", path, 7) == 0) {
+		return 1;
+	}
+	if (strncmp("https://", path, 8) == 0) {
+		return 1;
+	}
+	return 0;
+}
+
+int is_userhost_path(const char* path) {
+	// look for user at host:path
+	char *at = strchr(path, '@');
+	char *colon = strchr(path, ':');
+	return at && colon && at < colon;	
+}
+
 int has_suffix(const char* str, const char* sfx) {
 	str = strstr(str, sfx);
 	return (str && strcmp(str, sfx) == 0);
@@ -132,12 +151,13 @@
 	pid_t pid;
 	int status;
 	
-	pid = fork();
-	assert(pid != -1);
-	if (pid == 0) {
-		assert(execve(args[0], (char**)args, environ) != -1);
-		// NOT REACHED
-	}
+	IF_DEBUG("Spawning %s \n", args[0]);
+		
+	res = posix_spawn(&pid, args[0], NULL, NULL, (char**)args, environ);
+	if (res != 0) fprintf(stderr, "Error: Failed to spawn %s: %s (%d)\n", args[0], strerror(res), res);
+	
+	IF_DEBUG("Running %s on pid %d \n", args[0], (int)pid);
+
 	do {
 		res = waitpid(pid, &status, 0);
 	} while (res == -1 && errno == EINTR);
@@ -148,6 +168,9 @@
 			res = -1;
 		}
 	}
+	
+	IF_DEBUG("Done running %s \n", args[0]);
+	
 	return res;
 }
 
@@ -185,3 +208,40 @@
 	} 
 	return 0;
 }
+
+char* fetch_url(const char* srcpath, const char* dstpath) {
+	extern uint32_t verbosity;
+	char* localfile;
+	int res = join_path(&localfile, dstpath, basename((char*)srcpath));
+	if (res || !localfile) return NULL;
+	
+	const char* args[] = {
+		"/usr/bin/curl",
+		(verbosity ? "-v" : "-s"),
+		"-L", srcpath,
+		"-o", localfile,
+		NULL
+	};
+	if (res == 0) res = exec_with_args(args);
+	if (res == 0) return localfile;
+	return NULL;
+}
+
+char* fetch_userhost(const char* srcpath, const char* dstpath) {
+	extern uint32_t verbosity;
+	char* localfile;
+	int res = join_path(&localfile, dstpath, basename((char*)srcpath));
+	if (!localfile) return NULL;
+		
+	const char* args[] = {
+		"/usr/bin/rsync",
+		(verbosity ? "-v" : "-q"),
+		"-a", srcpath,
+		localfile,
+		NULL
+	};
+
+	if (res == 0) res = exec_with_args(args);
+	if (res == 0) return localfile;
+	return NULL;	
+}

Modified: trunk/darwinup/Utils.h
===================================================================
--- trunk/darwinup/Utils.h	2009-12-16 16:10:12 UTC (rev 665)
+++ trunk/darwinup/Utils.h	2009-12-16 18:16:43 UTC (rev 666)
@@ -48,12 +48,17 @@
 int remove_directory(const char* path);
 int is_directory(const char* path);
 int is_regular_file(const char* path);
+int is_url_path(const char* path);
+int is_userhost_path(const char* path);
 int has_suffix(const char* str, const char* sfx);
 int exec_with_args(const char** args);
 
 int join_path(char** out, const char* p1, const char* p2);
 int compact_slashes(char* orig, int slashes);
 
+char* fetch_url(const char* srcpath, const char* dstpath);
+char* fetch_userhost(const char* srcpath, const char* dstpath);
+
 inline int INFO_TEST(uint32_t word, uint32_t flag) { return ((word & flag) != 0); }
 inline int INFO_SET(uint32_t word, uint32_t flag) { return (word | flag); }
 inline int INFO_CLR(uint32_t word, uint32_t flag) { return (word & (~flag)); }

Modified: trunk/darwinup/main.cpp
===================================================================
--- trunk/darwinup/main.cpp	2009-12-16 16:10:12 UTC (rev 665)
+++ trunk/darwinup/main.cpp	2009-12-16 18:16:43 UTC (rev 666)
@@ -52,9 +52,29 @@
 	fprintf(stderr, "commands:                                                      \n");
 	fprintf(stderr, "          install    <path>                                    \n");
 	fprintf(stderr, "          list                                                 \n");
-	fprintf(stderr, "          files      <uuid>                                    \n");
-	fprintf(stderr, "          uninstall  <uuid>                                    \n");
-	fprintf(stderr, "          verify     <uuid>                                    \n");
+	fprintf(stderr, "          files      <archive>                                 \n");
+	fprintf(stderr, "          uninstall  <archive>                                 \n");
+	fprintf(stderr, "          verify     <archive>                                 \n");
+	fprintf(stderr, "                                                               \n");
+	fprintf(stderr, "<path> is one of:                                              \n");
+	fprintf(stderr, "          /path/to/local/dir-or-file                           \n");
+	fprintf(stderr, "          user at host:/path/to/remote/dir-or-file                \n");
+	fprintf(stderr, "          http[s]://host/path/to/remote/file                   \n");
+	fprintf(stderr, "                                                               \n");
+	fprintf(stderr, "Files must be in one of the supported archive formats:         \n");
+	fprintf(stderr, "          cpio, cpio.gz, cpio.bz2                              \n");
+	fprintf(stderr, "          pax, pax.gz, pax.bz2                                 \n");
+	fprintf(stderr, "          tar, tar.gz, tar.bz2                                 \n");
+	fprintf(stderr, "          xar, zip                                             \n");
+	fprintf(stderr, "                                                               \n");
+	fprintf(stderr, "<archive> is one of:                                           \n");
+	fprintf(stderr, "          <serial>   the Serial number                         \n");
+	fprintf(stderr, "          <uuid>     the UUID                                  \n");
+	fprintf(stderr, "          <name>     the last root installed with that name    \n");
+	fprintf(stderr, "          newest     the newest (last) root installed          \n");
+	fprintf(stderr, "          oldest     the oldest root installed                 \n");
+	fprintf(stderr, "          all        all installed roots                       \n");
+	fprintf(stderr, "                                                               \n");
 	exit(1);
 }
 
@@ -120,7 +140,7 @@
 	
 	if (argc == 2 && strcmp(argv[0], "install") == 0) {
 		char uuid[37];
-		Archive* archive = ArchiveFactory(argv[1]);
+		Archive* archive = ArchiveFactory(argv[1], depot->downloads_path());
 		if (archive) {
 			res = depot->install(archive);
 			if (res == 0) {
@@ -145,40 +165,11 @@
 	} else if (argc == 1 && strcmp(argv[0], "dump") == 0) {
 		depot->dump();
 	} else if (argc == 2 && strcmp(argv[0], "files") == 0) {
-		Archive* archive = depot->archive(argv[1]);
-		if (archive) {
-			res = depot->files(archive);
-			delete archive;
-		} else {
-			fprintf(stderr, "Archive not found: %s\n", argv[1]);
-			res = 1;
-		}
+		res = depot->process_archive(argv[0], argv[1]);
 	} else if (argc == 2 && strcmp(argv[0], "uninstall") == 0) {
-		Archive* archive = depot->archive(argv[1]);
-		if (archive) {
-			res = depot->uninstall(archive);
-			if (res != 0) {
-				fprintf(stderr, "An error occurred.\n");
-				res = 1;
-			}
-			delete archive;
-		} else {
-			fprintf(stderr, "Archive not found: %s\n", argv[1]);
-			res = 1;
-		}
+		res = depot->process_archive(argv[0], argv[1]);
 	} else if (argc == 2 && strcmp(argv[0], "verify") == 0) {
-		Archive* archive = depot->archive(argv[1]);
-		if (archive) {
-			res = depot->verify(archive);
-			if (res != 0) {
-				fprintf(stderr, "An error occurred.\n");
-				res = 1;
-			}
-			delete archive;
-		} else {
-			fprintf(stderr, "Archive not found: %s\n", argv[1]);
-			res = 1;
-		}
+		res = depot->process_archive(argv[0], argv[1]);
 	} else {
 		usage(progname);
 	}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/darwinbuild-changes/attachments/20091216/3e201c3e/attachment-0001.html>


More information about the darwinbuild-changes mailing list