1 /*
2  *             Copyright David Nadlinger 2014.
3  *  Distributed under the Boost Software License, Version 1.0.
4  *     (See accompanying file LICENSE_1_0.txt or copy at
5  *           http://www.boost.org/LICENSE_1_0.txt)
6  */
7 module git.clone;
8 
9 import git.checkout;
10 import git.credentials;
11 import git.remote;
12 import git.repository;
13 import git.transport;
14 import git.types;
15 import git.util;
16 import git.version_;
17 
18 import deimos.git2.clone;
19 import deimos.git2.remote;
20 import deimos.git2.transport;
21 import deimos.git2.types;
22 
23 ///
24 struct GitCloneOptions
25 {
26     uint version_ = git_clone_options.init.version_;
27 
28     GitCheckoutOptions checkoutOptions;
29 
30     bool cloneBare;
31 
32     static if (targetLibGitVersion == VersionInfo(0, 19, 0)) TransferCallbackDelegate fetchProgessCallback;
33 
34     string remoteName;
35     static if (targetLibGitVersion == VersionInfo(0, 19, 0)) {
36         string pushURL;
37         string fetchSpec;
38         string pushSpec;
39 
40         GitCredAcquireDelegate credAcquireCallback;
41 
42         GitTransportFlags transportFlags;
43         // GitTransport transport; // TODO: translate
44         // GitRemoteCallback[] remoteCallbacks; // TODO: implement translation
45         GitRemoteAutotagOption remoteAutotag;
46     }
47     string checkoutBranch;
48 }
49 
50 
51 static if (targetLibGitVersion == VersionInfo(0, 19, 0))  {
52     extern(C) nothrow int cFetchProgessCallback(
53         const(git_transfer_progress)* stats,
54         void* payload)
55     {
56         auto dg = (cast(GitCloneOptions*)payload).fetchProgessCallback;
57         if (dg) {
58             try {
59                 auto tp = GitTransferProgress(stats);
60                 dg(tp);
61             } catch (Exception e) {
62                 return -1;
63             }
64         }
65         return 0;
66     }
67 
68     extern(C) int cCredAcquireCallback(
69         git_cred** cred,
70         const(char)* url,
71         const(char)* username_from_url,
72         uint allowed_types,
73         void* payload)
74     {
75         auto dg = (cast(GitCloneOptions*)payload).credAcquireCallback;
76         if (dg)
77         {
78             auto dCred = dg(toSlice(url), toSlice(username_from_url), allowed_types);
79             // FIXME: cred will probably be immediately freed.
80             *cred = dCred.cHandle;
81             return 0;
82         }
83 
84         // FIXME: Use real error code here.
85         return 1;
86     }
87 }
88 
89 GitRepo cloneRepo(in char[] url, in char[] localPath, GitCloneOptions options = GitCloneOptions.init)
90 {
91     git_clone_options cOpts;
92     with (options)
93     {
94         cOpts.version_ = version_;
95         checkoutOptions.toCCheckoutOpts(cOpts.checkout_opts);
96         cOpts.bare = cloneBare;
97         static if (targetLibGitVersion == VersionInfo(0, 19, 0)) {
98             if (fetchProgessCallback)
99             {
100                 cOpts.fetch_progress_cb = &cFetchProgessCallback;
101                 cOpts.fetch_progress_payload = &cOpts;
102             }
103         }
104         cOpts.remote_name = remoteName.gitStr;
105         static if (targetLibGitVersion == VersionInfo(0, 19, 0)) {
106             cOpts.pushurl = pushURL.gitStr;
107             cOpts.fetch_spec = fetchSpec.gitStr;
108             cOpts.push_spec = pushSpec.gitStr;
109             if (credAcquireCallback)
110             {
111                 cOpts.cred_acquire_cb = &cCredAcquireCallback;
112                 cOpts.cred_acquire_payload = &cOpts;
113             }
114             cOpts.transport_flags = transportFlags;
115             // cOpts.transport = // TODO: Translate.
116             cOpts.remote_autotag = cast(git_remote_autotag_option_t)remoteAutotag;
117         }
118         cOpts.checkout_branch = checkoutBranch.gitStr;
119     }
120 
121     git_repository* repo;
122     auto errc = git_clone(&repo, url.gitStr, localPath.gitStr, &cOpts);
123     require(errc == 0);
124     return GitRepo(repo);
125 }