1 module repo;
2 
3 import std.array;
4 import std.algorithm;
5 import std.exception;
6 import std.file;
7 import std.parallelism : parallel;
8 import std.path;
9 import std.process;
10 import std.range;
11 import std.regex;
12 import std..string;
13 
14 import ae.sys.file;
15 import ae.sys.d.manager;
16 
17 import common;
18 import config : config, opts;
19 import custom : parseSpec;
20 
21 //alias BuildConfig = DManager.Config.Build;
22 
23 final class DiggerManager : DManager
24 {
25 	this()
26 	{
27 		this.config.build = cast().config.build;
28 		this.config.local = cast().config.local;
29 		this.verifyWorkTree = true; // for commands which don't take BuildOptions, like bisect
30 	}
31 
32 	override void log(string s)
33 	{
34 		common.log(s);
35 	}
36 
37 	void logProgress(string s)
38 	{
39 		log((" " ~ s ~ " ").center(70, '-'));
40 	}
41 
42 	override SubmoduleState parseSpec(string spec)
43 	{
44 		return .parseSpec(spec);
45 	}
46 
47 	override MetaRepository getMetaRepo()
48 	{
49 		if (!repoDir.exists)
50 			log("First run detected.\nPlease be patient, " ~
51 				"cloning everything might take a few minutes...\n");
52 		return super.getMetaRepo();
53 	}
54 
55 	override string getCallbackCommand()
56 	{
57 		return escapeShellFileName(thisExePath) ~ " do callback";
58 	}
59 
60 	string[string] getBaseEnvironment()
61 	{
62 		return d.baseEnvironment.vars;
63 	}
64 
65 	bool haveUpdate;
66 
67 	void needUpdate()
68 	{
69 		if (!haveUpdate)
70 		{
71 			d.update();
72 			haveUpdate = true;
73 		}
74 	}
75 }
76 
77 DiggerManager d;
78 
79 static this()
80 {
81 	d = new DiggerManager();
82 }
83 
84 string parseRev(string rev)
85 {
86 	auto args = ["log", "--pretty=format:%H"];
87 
88 	d.needUpdate();
89 
90 	auto metaRepo = d.getMetaRepo();
91 	auto repo = &metaRepo.git();
92 
93 	// git's approxidate accepts anything, so a disambiguating prefix is required
94 	if (rev.canFind('@') && !rev.canFind("@{"))
95 	{
96 		auto parts = rev.findSplit("@");
97 		auto at = parts[2].strip();
98 
99 		// If this is a named tag, use the date of the tagged commit.
100 		try
101 		{
102 			auto sha1 = metaRepo.getRef("refs/tags/" ~ at);
103 			at = repo.query("log", "-1", "--pretty=format:%cI", sha1);
104 		}
105 		catch (Exception e) {}
106 
107 		if (at.startsWith("#")) // For the build-all command - skip this many commits
108 			args ~= ["--skip", at[1..$]];
109 		else
110 			args ~= ["--until", at];
111 		rev = parts[0].strip();
112 	}
113 
114 	if (rev.empty)
115 		rev = "origin/master";
116 
117 	try
118 		return repo.query(args ~ ["-n", "1", "origin/" ~ rev]);
119 	catch (Exception e)
120 	try
121 		return repo.query(args ~ ["-n", "1", rev]);
122 	catch (Exception e)
123 		{}
124 
125 	auto grep = repo.query("log", "-n", "2", "--pretty=format:%H", "--grep", rev, "origin/master").splitLines();
126 	if (grep.length == 1)
127 		return grep[0];
128 
129 	auto pickaxe = repo.query("log", "-n", "3", "--pretty=format:%H", "-S" ~ rev, "origin/master").splitLines();
130 	if (pickaxe.length && pickaxe.length <= 2) // removed <- added
131 		return pickaxe[$-1];   // the one where it was added
132 
133 	throw new Exception("Unknown/ambiguous revision: " ~ rev);
134 }