Index: GetComponents
===================================================================
--- GetComponents	(revision 600)
+++ GetComponents	(working copy)
@@ -58,21 +58,25 @@
 my $cvs = 'cvs';
 my $svn = 'svn';
 my $git = 'git';
+my $darcs = 'darcs';
 my $wget = 'wget';
 my $hg = 'hg';
 my $curl = 'curl';
 my $cvs_found = 0;
 my $svn_found = 0;
 my $git_found = 0;
+my $darcs_found = 0;
 my $wget_found = 0;
 my $curl_found = 0;
 my $hg_found = 0;
 my %updated_git_repos;
+my %updated_darcs_repos;
 my %updated_hg_repos;
 my %checkout_types = (
         'cvs'       => \&handle_cvs,
         'svn'       => \&handle_svn,
         'git'       => \&handle_git,
+        'darcs'     => \&handle_darcs,
         'http'      => \&handle_wget,
         'https'     => \&handle_wget,
         'ftp'       => \&handle_wget,
@@ -178,6 +182,7 @@
         $curl_found = 1;
     }
     elsif (run_command("which wget") == 0) {$wget_found = 1}
+    if (run_command("which darcs") == 0) {$darcs_found = 1}
     if (run_command("which hg") == 0) {$hg_found = 1}
 }
 
@@ -347,6 +352,12 @@
                 $wget_found = 1;
             }
         }
+        if (($rec{"TYPE"} eq "darcs") && (!$darcs_found)) {
+            print "You have requested a darcs checkout, but the system was unable to find darcs.\n";
+            print "Please enter the path to darcs: ";
+            $darcs = <STDIN>;
+            chomp $darcs;
+        }
         if (($rec{"TYPE"} eq "hg") && (!$hg_found)) {
             print "You have requested an hg checkout, but the system was unable to find hg.\n";
             print "Please enter the path to hg: ";
@@ -366,6 +377,18 @@
             $updated_git_repos{$git_repo} = 0;
         }
         
+        # parse name of darcs repo
+        if ($rec{"TYPE"} eq "darcs") {
+            my $darcs_repo = $rec{"URL"};
+            $darcs_repo =~ s/_darcs$//;
+            $darcs_repo =~ s/^.*[:\/]//;
+            $rec{"DARCS_REPO"} = $darcs_repo;
+            # add the repo to %updated_darcs_repos and set it to 0
+            # we will use this to track which repos have already been cloned
+            # or updated
+            $updated_darcs_repos{$darcs_repo} = 0;
+        }
+        
         # parse name of mercurial repo
         if ($rec{"TYPE"} eq "hg") {
             my $hg_repo = $rec{"URL"};
@@ -431,6 +454,10 @@
             elsif ($component{"TYPE"} eq "git" && -e "$target/$dir") {
                 push @components_to_update, \%component;
             }
+            # and for darcs
+            elsif ($component{"TYPE"} eq "darcs" && -e "$target/$dir") {
+                push @components_to_update, \%component;
+            }
             # and for hg
             elsif ($component{"TYPE"} eq "hg" && -e "$target/$dir") {
                 push @components_to_update, \%component;
@@ -472,6 +499,7 @@
         if (defined($component->{AUTH_URL}) and
              ($component->{TYPE} eq 'cvs' or
              $component->{TYPE} eq 'svn' or
+             $component->{TYPE} eq 'darcs' or
              $component->{TYPE} eq 'git')) {
              
             # if AUTH_URL is in the form xxx@xxx the user is included
@@ -745,6 +773,7 @@
     my $repo_path = $component{"REPO_PATH"}; 
     my $git_repo = $component{"GIT_REPO"};
     my $cmd = '';
+    my $git_repos_dir = '';
 
     if ($method eq 'checkout') {
                 
@@ -768,28 +797,36 @@
         # anyway to suggest that we didn't miss a module
         else {print_checkout_info($checkout, $url, $target, $name)}
         
+        my($checkout_dir, $checkout_item) = split(/\//, $checkout);
+        # get relative path from target directory to directory containing the repositories
+        $git_repos_dir = File::Spec->abs2rel("$ROOT/git-repos", "$target/$checkout_dir");
         # have to chdir to checkout dir for link to work properly      
-        my($checkout_dir, $checkout_item) = split(/\//, $checkout);
-        run_command("mkdir -p $target/$checkout_dir");
-        chdir("$target/$checkout_dir");
+        if ($checkout =~ /\//) {    
+            run_command("mkdir -p $target/$checkout_dir");
+            chdir("$target/$checkout_dir");
+        }
+        else {
+            chdir("$target");
+            $checkout_item = $checkout;
+        }
         
         # now we create a symlink from the repo to the appropriate target
         if (defined($repo_path)) {
             if ($repo_path =~ /\$2/) {
                 $checkout =~ m!(.*)/(.*)!;
                 $repo_path = $2;
-                $cmd = "ln -s ../../git-repos/$git_repo/$repo_path $checkout_item";
+                $cmd = "ln -s $git_repos_dir/$git_repo/$repo_path $checkout_item";
                 if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
             }
             else {
-                $cmd = "ln -s ../../git-repos/$git_repo/$repo_path/$checkout $checkout_item";
+                $cmd = "ln -s $git_repos_dir/$git_repo/$repo_path/$checkout $checkout_item";
                 if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
             }
             return if (-e "$checkout_item");
             run_command($cmd);
         }
         else {
-            $cmd = "ln -s ../../git-repos/$git_repo/$checkout $checkout_item";
+            $cmd = "ln -s $git_repos_dir/$git_repo/$checkout $checkout_item";
             if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
             return if (-e "$checkout_item");
             run_command($cmd);
@@ -898,6 +935,103 @@
     else {DIE("Unrecognized checkout method: $method")}           
 }
 
+sub handle_darcs
+{
+    my ($method, %component) = @_;
+    my $target = $component{"TARGET"};
+    my $name = $component{"NAME"};
+    my $url = $component{"URL"};
+    if (defined($component{"AUTH_URL"})) {
+        $url = $component{"AUTH_URL"};
+    }
+    my $checkout = $component{"CHECKOUT"};
+    my $repo_path = $component{"REPO_PATH"}; 
+    my $darcs_repo = $component{"DARCS_REPO"};
+    my $cmd = '';
+    my $darcs_repos_dir = '';
+
+    if ($method eq 'checkout') {
+                
+        run_command("mkdir -p $ROOT/darcs-repos");
+        # clone the darcs repo
+        if (! -e "$ROOT/darcs-repos/$darcs_repo") {
+            $cmd = "$darcs clone $url $ROOT/darcs-repos/$darcs_repo";
+            print_checkout_info($checkout, $url, $target, $name);
+            run_command($cmd) == 0 or push (@components_error, $checkout);
+            $updated_darcs_repos{$darcs_repo} = 1;
+        }
+        # if darcs repo has already been cloned, we will pull the latest version
+        elsif ($updated_darcs_repos{$darcs_repo} == 0) {
+            chdir("$ROOT/darcs-repos/$darcs_repo");
+            print_checkout_info($checkout, $url, $target, $name);
+            run_command("$darcs pull") == 0 or push (@components_error, $checkout);
+            $updated_darcs_repos{$darcs_repo} = 1;
+            chdir($orig_dir)
+        }
+        # if darcs repo has already been updated, we will print checkout info 
+        # anyway to suggest that we didn't miss a module
+        else {print_checkout_info($checkout, $url, $target, $name)}
+        
+        my($checkout_dir, $checkout_item) = split(/\//, $checkout);
+        # get relative path from target directory to directory containing the repositories
+        $darcs_repos_dir = File::Spec->abs2rel("$ROOT/darcs-repos", "$target/$checkout_dir");
+        # have to chdir to checkout dir for link to work properly      
+        if ($checkout =~ /\//) {    
+            run_command("mkdir -p $target/$checkout_dir");
+            chdir("$target/$checkout_dir");
+        }
+        else {
+            chdir("$target");
+            $checkout_item = $checkout;
+        }
+        
+        # now we create a symlink from the repo to the appropriate target
+        if (defined($repo_path)) {
+            if ($repo_path =~ /\$2/) {
+                $checkout =~ m!(.*)/(.*)!;
+                $repo_path = $2;
+                $cmd = "ln -s $darcs_repos_dir/$darcs_repo/$repo_path $checkout_item";
+                if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
+            }
+            else {
+                $cmd = "ln -s $darcs_repos_dir/$darcs_repo/$repo_path/$checkout $checkout_item";
+                if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
+            }
+            return if (-e "$checkout_item");
+            run_command($cmd);
+        }
+        else {
+            $cmd = "ln -s $darcs_repos_dir/$darcs_repo/$checkout $checkout_item";
+            if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
+            return if (-e "$checkout_item");
+            run_command($cmd);
+        }
+    }   
+    
+    elsif ($method eq 'update') {
+        
+        if ($updated_darcs_repos{$darcs_repo} == 0) {
+            chdir("$ROOT/darcs-repos/$darcs_repo");
+            print_update_info($checkout, $url, $target, $name);
+            run_command("$darcs pull") == 0 or push (@components_error, $checkout);
+            $updated_darcs_repos{$darcs_repo} = 1;
+            chdir($orig_dir)
+        }
+        # if darcs repo has already been updated print update info anyway 
+        # to suggest that we didn't miss a module
+        else {print_update_info($checkout, $url, $target, $name)}
+    }
+    
+    elsif ($method eq 'authenticate') {
+        # do something, nothing for now...
+        # darcs authenticates through ssh, so no storing usernames and stuff yet
+        my $user = $component{USER};
+        save_user($user, $url);
+    }
+    
+    else {DIE("Unrecognized checkout method: $method")}             
+}
+
 sub handle_wget
 {
     my ($method, %component) = @_;   
@@ -987,6 +1121,7 @@
     my $repo_path = $component{"REPO_PATH"}; 
     my $hg_repo = $component{"HG_REPO"};
     my $cmd = '';
+    my $hg_repos_dir = '';
 
     if ($method eq 'checkout') {
     
@@ -1012,8 +1147,10 @@
         # anyway to suggest that we didn't miss a module
         else {print_checkout_info($checkout, $url, $target, $name)}
         
+        my($checkout_dir, $checkout_item) = split(/\//, $checkout);
+        # get relative path from target directory to directory containing the repositories
+        $hg_repos_dir = File::Spec->abs2rel("$ROOT/hg-repos", "$target/$checkout_dir");
         # have to chdir to checkout dir for link to work properly  
-        my($checkout_dir, $checkout_item) = split(/\//, $checkout);
         if ($checkout =~ /\//) {    
             run_command("mkdir -p $target/$checkout_dir");
             chdir("$target/$checkout_dir");
@@ -1028,18 +1165,18 @@
             if ($repo_path =~ /\$2/) {
                 $checkout =~ m!(.*)/(.*)!;
                 $repo_path = $2;
-                $cmd = "ln -s ../../hg-repos/$hg_repo/$repo_path $checkout_item";
+                $cmd = "ln -s $hg_repos_dir/$hg_repo/$repo_path $checkout_item";
                 if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
             }
             else {
-                $cmd = "ln -s ../../hg-repos/$hg_repo/$repo_path/$checkout $checkout_item";
+                $cmd = "ln -s $hg_repos_dir/$hg_repo/$repo_path/$checkout $checkout_item";
                 if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
             }
             return if (-e "$checkout_item");
             run_command($cmd);
         }
         else {
-            $cmd = "ln -s ../../hg-repos/$hg_repo/$checkout $checkout_item";
+            $cmd = "ln -s $hg_repos_dir/$hg_repo/$checkout $checkout_item";
             if ($orig_dir eq $ROOT) {$cmd =~ s!$orig_dir/!!}
             return if (-e "$checkout_item");
             run_command($cmd);
@@ -1083,6 +1220,7 @@
         while (<$output>) {
             print;
         }
+        close ($output); # to get $?
         LOG("Could not run command: $command, because of $!") if $?;
         return $?;
     }
@@ -1096,6 +1234,7 @@
         while (<$output>) {
             print;
         }
+        close ($output); # to get $?
         LOG("Could not run command: $command, because of $!") if $?;
         return $?;
     }
@@ -1103,6 +1242,7 @@
     else {
         open (my $output, "$command 1>/dev/null 2>&1 |");
         while (<$output>) { }
+        close ($output); # to get $?
         LOG("Could not run command: $command, because of $!") if $?;
         return $?;
    }
@@ -1260,7 +1400,7 @@
 
 =head1 DESCRIPTION
 
-B<This program> will parse the given input file(s), and checkout/update the requested components using cvs, svn, git, hg, http, https, and ftp. It requires an argument specifying the file that will contain the information required to checkout the components. Multiple files may be passed together. A component list may also be specified as the URL where the list is located, in which case GetComponents will download the component list, and then proceed as usual.
+B<This program> will parse the given input file(s), and checkout/update the requested components using cvs, svn, git, darcs, hg, http, https, and ftp. It requires an argument specifying the file that will contain the information required to checkout the components. Multiple files may be passed together. A component list may also be specified as the URL where the list is located, in which case GetComponents will download the component list, and then proceed as usual.
 
 This file must have the following syntax:
 
