]> git.lizzy.rs Git - rust.git/blob - src/etc/snapshot.py
Rollup merge of #21336 - rylev:better-nofile-error, r=brson
[rust.git] / src / etc / snapshot.py
1 # Copyright 2011-2014 The Rust Project Developers. See the COPYRIGHT
2 # file at the top-level directory of this distribution and at
3 # http://rust-lang.org/COPYRIGHT.
4 #
5 # Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 # http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 # <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 # option. This file may not be copied, modified, or distributed
9 # except according to those terms.
10
11 import re, os, sys, glob, tarfile, shutil, subprocess, tempfile, distutils.spawn
12
13 try:
14   import hashlib
15   sha_func = hashlib.sha1
16 except ImportError:
17   import sha
18   sha_func = sha.new
19
20 def scrub(b):
21   if sys.version_info >= (3,) and type(b) == bytes:
22     return b.decode('ascii')
23   else:
24     return b
25
26 src_dir = scrub(os.getenv("CFG_SRC_DIR"))
27 if not src_dir:
28   raise Exception("missing env var CFG_SRC_DIR")
29
30 snapshotfile = os.path.join(src_dir, "src", "snapshots.txt")
31 download_url_base = "https://static.rust-lang.org/stage0-snapshots"
32 download_dir_base = "dl"
33 download_unpack_base = os.path.join(download_dir_base, "unpack")
34
35 snapshot_files = {
36     "linux": ["bin/rustc"],
37     "macos": ["bin/rustc"],
38     "winnt": ["bin/rustc.exe"],
39     "freebsd": ["bin/rustc"],
40     "dragonfly": ["bin/rustc"],
41     }
42
43 winnt_runtime_deps_32 = ["libgcc_s_dw2-1.dll",
44                          "libstdc++-6.dll"]
45 winnt_runtime_deps_64 = ["libgcc_s_seh-1.dll",
46                          "libstdc++-6.dll"]
47
48 def parse_line(n, line):
49   global snapshotfile
50
51   if re.match(r"\s*$", line): return None
52
53   if re.match(r"^T\s*$", line): return None
54
55   match = re.match(r"\s+([\w_-]+) ([a-fA-F\d]{40})\s*$", line)
56   if match:
57     return { "type": "file",
58              "platform": match.group(1),
59              "hash": match.group(2).lower() }
60
61   match = re.match(r"([ST]) (\d{4}-\d{2}-\d{2}) ([a-fA-F\d]+)\s*$", line);
62   if (not match):
63     raise Exception("%s:%d:E syntax error: " % (snapshotfile, n))
64   return {"type": "snapshot",
65           "date": match.group(2),
66           "rev": match.group(3)}
67
68
69 def partial_snapshot_name(date, rev, platform):
70   return ("rust-stage0-%s-%s-%s.tar.bz2"
71           % (date, rev, platform))
72
73 def full_snapshot_name(date, rev, platform, hsh):
74   return ("rust-stage0-%s-%s-%s-%s.tar.bz2"
75           % (date, rev, platform, hsh))
76
77
78 def get_kernel(triple):
79     t = triple.split('-')
80     if len(t) == 2:
81       os_name = t[1]
82     else:
83       os_name = t[2]
84     if os_name == "windows":
85         return "winnt"
86     if os_name == "darwin":
87         return "macos"
88     if os_name == "freebsd":
89         return "freebsd"
90     if os_name == "dragonfly":
91         return "dragonfly"
92     return "linux"
93
94 def get_cpu(triple):
95     arch = triple.split('-')[0]
96     if arch == "i686":
97       return "i386"
98     return arch
99
100 def get_platform(triple):
101   return "%s-%s" % (get_kernel(triple), get_cpu(triple))
102
103
104 def cmd_out(cmdline):
105     p = subprocess.Popen(cmdline,
106                          stdout=subprocess.PIPE)
107     return scrub(p.communicate()[0].strip())
108
109
110 def local_rev_info(field):
111     return cmd_out(["git", "--git-dir=" + os.path.join(src_dir, ".git"),
112                     "log", "-n", "1",
113                     "--format=%%%s" % field, "HEAD"])
114
115
116 def local_rev_full_sha():
117     return local_rev_info("H").split()[0]
118
119
120 def local_rev_short_sha():
121     return local_rev_info("h").split()[0]
122
123
124 def local_rev_committer_date():
125     return local_rev_info("ci")
126
127 def get_url_to_file(u,f):
128     # no security issue, just to stop partial download leaving a stale file
129     tmpf = f + '.tmp'
130
131     returncode = -1
132     if distutils.spawn.find_executable("curl"):
133         returncode = subprocess.call(["curl", "-o", tmpf, u])
134     elif distutils.spawn.find_executable("wget"):
135         returncode = subprocess.call(["wget", "-O", tmpf, u])
136
137     if returncode != 0:
138         try:
139             os.unlink(tmpf)
140         except OSError as e:
141             pass
142         raise Exception("failed to fetch url")
143     os.rename(tmpf, f)
144
145 def snap_filename_hash_part(snap):
146   match = re.match(r".*([a-fA-F\d]{40}).tar.bz2$", snap)
147   if not match:
148     raise Exception("unable to find hash in filename: " + snap)
149   return match.group(1)
150
151 def hash_file(x):
152     h = sha_func()
153     h.update(open(x, "rb").read())
154     return scrub(h.hexdigest())
155
156 # Returns a list of paths of Rust's system runtime dependencies
157 def get_winnt_runtime_deps(platform):
158     if platform == "winnt-x86_64":
159       deps = winnt_runtime_deps_64
160     else:
161       deps = winnt_runtime_deps_32
162     runtime_deps = []
163     path_dirs = os.environ["PATH"].split(os.pathsep)
164     for name in deps:
165       for dir in path_dirs:
166         filepath = os.path.join(dir, name)
167         if os.path.isfile(filepath):
168           runtime_deps.append(filepath)
169           break
170       else:
171         raise Exception("Could not find runtime dependency: %s" % name)
172     return runtime_deps
173
174 def make_snapshot(stage, triple):
175     kernel = get_kernel(triple)
176     platform = get_platform(triple)
177     rev = local_rev_short_sha()
178     date = local_rev_committer_date().split()[0]
179
180     file0 = partial_snapshot_name(date, rev, platform)
181
182     def in_tar_name(fn):
183       cs = re.split(r"[\\/]", fn)
184       if len(cs) >= 2:
185         return os.sep.join(cs[-2:])
186
187     tar = tarfile.open(file0, "w:bz2")
188
189     for name in snapshot_files[kernel]:
190       dir = stage
191       if stage == "stage1" and re.match(r"^lib/(lib)?std.*", name):
192         dir = "stage0"
193       fn_glob = os.path.join(triple, dir, name)
194       matches = glob.glob(fn_glob)
195       if not matches:
196         raise Exception("Not found file with name like " + fn_glob)
197       if len(matches) == 1:
198         tar.add(matches[0], "rust-stage0/" + in_tar_name(matches[0]))
199       else:
200         raise Exception("Found stale files: \n  %s\n"
201                         "Please make a clean build." % "\n  ".join(matches))
202
203     if kernel=="winnt":
204       for path in get_winnt_runtime_deps(platform):
205         tar.add(path, "rust-stage0/bin/" + os.path.basename(path))
206       tar.add(os.path.join(os.path.dirname(__file__), "third-party"),
207               "rust-stage0/bin/third-party")
208
209     tar.close()
210
211     h = hash_file(file0)
212     file1 = full_snapshot_name(date, rev, platform, h)
213
214     shutil.move(file0, file1)
215
216     return file1
217
218 def curr_snapshot_rev():
219   i = 0
220   found_snap = False
221   date = None
222   rev = None
223
224   f = open(snapshotfile)
225   for line in f.readlines():
226     i += 1
227     parsed = parse_line(i, line)
228     if (not parsed): continue
229
230     if parsed["type"] == "snapshot":
231       date = parsed["date"]
232       rev = parsed["rev"]
233       found_snap = True
234       break
235
236   if not found_snap:
237     raise Exception("no snapshot entries in file")
238
239   return (date, rev)
240
241 def determine_curr_snapshot(triple):
242   i = 0
243   platform = get_platform(triple)
244
245   found_file = False
246   found_snap = False
247   hsh = None
248   date = None
249   rev = None
250
251   f = open(snapshotfile)
252   for line in f.readlines():
253     i += 1
254     parsed = parse_line(i, line)
255     if (not parsed): continue
256
257     if found_snap and parsed["type"] == "file":
258       if parsed["platform"] == platform:
259         hsh = parsed["hash"]
260         found_file = True
261         break;
262     elif parsed["type"] == "snapshot":
263       date = parsed["date"]
264       rev = parsed["rev"]
265       found_snap = True
266
267   if not found_snap:
268     raise Exception("no snapshot entries in file")
269
270   if not found_file:
271     raise Exception("no snapshot file found for platform %s, rev %s" %
272                     (platform, rev))
273
274   return full_snapshot_name(date, rev, platform, hsh)