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