| ... | ... | @@ -242,20 +242,6 @@ fn parseAt(time_part: string, tz_part: string) time.DateTime { |
| 242 | 242 | return at; |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | | pub const Commit = struct { |
| 246 | | tree: TreeId, |
| 247 | | parents: []const CommitId, |
| 248 | | author: UserAndAt, |
| 249 | | committer: UserAndAt, |
| 250 | | message: string, |
| 251 | | }; |
| 252 | | |
| 253 | | pub const UserAndAt = struct { |
| 254 | | name: string, |
| 255 | | email: string, |
| 256 | | at: time.DateTime, |
| 257 | | }; |
| 258 | | |
| 259 | 245 | fn parseTreeMode(input: string) !Tree.Object.Mode { |
| 260 | 246 | const t = tracer.trace(@src(), "", .{}); |
| 261 | 247 | defer t.end(); |
| ... | ... | @@ -269,133 +255,6 @@ fn parseTreeMode(input: string) !Tree.Object.Mode { |
| 269 | 255 | }; |
| 270 | 256 | } |
| 271 | 257 | |
| 272 | | pub const Tree = struct { |
| 273 | | children: MultiArrayList(Object), |
| 274 | | |
| 275 | | pub fn get(self: Tree, name: string) ?Object { |
| 276 | | if (self.children.len() <= 1000) { |
| 277 | | for (self.children.items.name, 0..) |a_name, i| { |
| 278 | | if (std.mem.eql(u8, a_name, name)) { |
| 279 | | return self.children.get(i); |
| 280 | | } |
| 281 | | } |
| 282 | | return null; |
| 283 | | } |
| 284 | | const i = std.sort.binarySearch([]const u8, self.children.items.name, name, extras.compareFnSlice(u8)) orelse return null; |
| 285 | | return self.children.get(i); |
| 286 | | } |
| 287 | | |
| 288 | | pub fn getBlob(self: Tree, name: string) ?Object { |
| 289 | | const o = self.get(name) orelse return null; |
| 290 | | if (o.id != .blob) return null; |
| 291 | | return o; |
| 292 | | } |
| 293 | | |
| 294 | | pub fn find(self: Tree, name: string) ?Object { |
| 295 | | for (self.children.items.name, 0..) |item, i| { |
| 296 | | if (std.ascii.eqlIgnoreCase(item, name)) { |
| 297 | | return self.children.get(i); |
| 298 | | } |
| 299 | | } |
| 300 | | return null; |
| 301 | | } |
| 302 | | |
| 303 | | pub fn findBlob(self: Tree, name: string) ?Object { |
| 304 | | const o = self.find(name) orelse return null; |
| 305 | | if (o.id != .blob) return null; |
| 306 | | return o; |
| 307 | | } |
| 308 | | |
| 309 | | pub const Object = struct { |
| 310 | | mode: Mode, |
| 311 | | id: AnyId, |
| 312 | | name: [:0]const u8, |
| 313 | | |
| 314 | | pub const Mode = struct { |
| 315 | | type: Type, |
| 316 | | perm_user: Perm, |
| 317 | | perm_group: Perm, |
| 318 | | perm_other: Perm, |
| 319 | | |
| 320 | | pub fn format(self: Mode, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 321 | | _ = fmt; |
| 322 | | _ = options; |
| 323 | | try writer.print("{}", .{self.type}); |
| 324 | | try writer.print("{}", .{self.perm_user}); |
| 325 | | try writer.print("{}", .{self.perm_group}); |
| 326 | | try writer.print("{}", .{self.perm_other}); |
| 327 | | } |
| 328 | | |
| 329 | | pub fn nprint(self: Mode, writer: anytype) !void { |
| 330 | | try self.type.nprint(writer); |
| 331 | | try self.perm_user.nprint(writer); |
| 332 | | try self.perm_group.nprint(writer); |
| 333 | | try self.perm_other.nprint(writer); |
| 334 | | } |
| 335 | | |
| 336 | | pub fn eql(self: Mode, other: Mode) bool { |
| 337 | | if (self.type != other.type) return false; |
| 338 | | if (self.perm_user != other.perm_user) return false; |
| 339 | | if (self.perm_group != other.perm_group) return false; |
| 340 | | if (self.perm_other != other.perm_other) return false; |
| 341 | | return true; |
| 342 | | } |
| 343 | | }; |
| 344 | | |
| 345 | | pub const Type = enum(u8) { |
| 346 | | file = 100, |
| 347 | | directory = 40, |
| 348 | | submodule = 160, |
| 349 | | symlink = 120, |
| 350 | | none = 0, |
| 351 | | |
| 352 | | pub fn format(self: Type, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 353 | | _ = fmt; |
| 354 | | _ = options; |
| 355 | | try writer.writeByte(switch (self) { |
| 356 | | .file => '-', |
| 357 | | .directory => 'd', |
| 358 | | .submodule => 'm', |
| 359 | | .symlink => '-', |
| 360 | | .none => '-', |
| 361 | | }); |
| 362 | | } |
| 363 | | |
| 364 | | pub fn nprint(self: Type, writer: anytype) !void { |
| 365 | | try writer.writeAll(&.{switch (self) { |
| 366 | | .file => '-', |
| 367 | | .directory => 'd', |
| 368 | | .submodule => 'm', |
| 369 | | .symlink => '-', |
| 370 | | .none => '-', |
| 371 | | }}); |
| 372 | | } |
| 373 | | }; |
| 374 | | |
| 375 | | pub const Perm = packed struct(u3) { |
| 376 | | execute: bool, |
| 377 | | write: bool, |
| 378 | | read: bool, |
| 379 | | |
| 380 | | pub fn format(self: Perm, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 381 | | _ = fmt; |
| 382 | | _ = options; |
| 383 | | try writer.writeByte(if (self.read) 'r' else '-'); |
| 384 | | try writer.writeByte(if (self.write) 'w' else '-'); |
| 385 | | try writer.writeByte(if (self.execute) 'x' else '-'); |
| 386 | | } |
| 387 | | |
| 388 | | pub fn nprint(self: Perm, writer: anytype) !void { |
| 389 | | try writer.writeAll(&.{ |
| 390 | | if (self.read) 'r' else '-', |
| 391 | | if (self.write) 'w' else '-', |
| 392 | | if (self.execute) 'x' else '-', |
| 393 | | }); |
| 394 | | } |
| 395 | | }; |
| 396 | | }; |
| 397 | | }; |
| 398 | | |
| 399 | 258 | // TODO make this inspect .git manually |
| 400 | 259 | // TODO make this return a Reader when we implement it ourselves |
| 401 | 260 | pub fn getTreeDiff(alloc: std.mem.Allocator, dir: nfs.Dir, commitid: CommitId, parentid: ?CommitId) !string { |
| ... | ... | @@ -685,11 +544,6 @@ pub const TreeDiff = struct { |
| 685 | 544 | }; |
| 686 | 545 | }; |
| 687 | 546 | |
| 688 | | pub const Ref = struct { |
| 689 | | oid: Id, |
| 690 | | label: string, |
| 691 | | }; |
| 692 | | |
| 693 | 547 | pub fn parseTag(tagfile: string) !Tag { |
| 694 | 548 | const t = tracer.trace(@src(), "", .{}); |
| 695 | 549 | defer t.end(); |
| ... | ... | @@ -716,13 +570,6 @@ pub fn parseTag(tagfile: string) !Tag { |
| 716 | 570 | return result; |
| 717 | 571 | } |
| 718 | 572 | |
| 719 | | pub const Tag = struct { |
| 720 | | object: Id, |
| 721 | | type: RefType, |
| 722 | | tagger: ?UserAndAt, |
| 723 | | message: string, |
| 724 | | }; |
| 725 | | |
| 726 | 573 | // TODO make this inspect .git/objects |
| 727 | 574 | pub fn getBlame(alloc: std.mem.Allocator, dir: nfs.Dir, at: CommitId, sub_path: string) !string { |
| 728 | 575 | const t = tracer.trace(@src(), " {s} -- {s}", .{ at.id, sub_path }); |
| ... | ... | @@ -1493,6 +1340,159 @@ fn traverseTo(r: *Repository, arena: std.mem.Allocator, treestart_id: TreeId, di |
| 1493 | 1340 | return tree; |
| 1494 | 1341 | } |
| 1495 | 1342 | |
| 1343 | pub const Tree = struct { |
| 1344 | children: MultiArrayList(Object), |
| 1345 | |
| 1346 | pub fn get(self: Tree, name: string) ?Object { |
| 1347 | if (self.children.len() <= 1000) { |
| 1348 | for (self.children.items.name, 0..) |a_name, i| { |
| 1349 | if (std.mem.eql(u8, a_name, name)) { |
| 1350 | return self.children.get(i); |
| 1351 | } |
| 1352 | } |
| 1353 | return null; |
| 1354 | } |
| 1355 | const i = std.sort.binarySearch([]const u8, self.children.items.name, name, extras.compareFnSlice(u8)) orelse return null; |
| 1356 | return self.children.get(i); |
| 1357 | } |
| 1358 | |
| 1359 | pub fn getBlob(self: Tree, name: string) ?Object { |
| 1360 | const o = self.get(name) orelse return null; |
| 1361 | if (o.id != .blob) return null; |
| 1362 | return o; |
| 1363 | } |
| 1364 | |
| 1365 | pub fn find(self: Tree, name: string) ?Object { |
| 1366 | for (self.children.items.name, 0..) |item, i| { |
| 1367 | if (std.ascii.eqlIgnoreCase(item, name)) { |
| 1368 | return self.children.get(i); |
| 1369 | } |
| 1370 | } |
| 1371 | return null; |
| 1372 | } |
| 1373 | |
| 1374 | pub fn findBlob(self: Tree, name: string) ?Object { |
| 1375 | const o = self.find(name) orelse return null; |
| 1376 | if (o.id != .blob) return null; |
| 1377 | return o; |
| 1378 | } |
| 1379 | |
| 1380 | pub const Object = struct { |
| 1381 | mode: Mode, |
| 1382 | id: AnyId, |
| 1383 | name: [:0]const u8, |
| 1384 | |
| 1385 | pub const Mode = struct { |
| 1386 | type: Type, |
| 1387 | perm_user: Perm, |
| 1388 | perm_group: Perm, |
| 1389 | perm_other: Perm, |
| 1390 | |
| 1391 | pub fn format(self: Mode, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 1392 | _ = fmt; |
| 1393 | _ = options; |
| 1394 | try writer.print("{}", .{self.type}); |
| 1395 | try writer.print("{}", .{self.perm_user}); |
| 1396 | try writer.print("{}", .{self.perm_group}); |
| 1397 | try writer.print("{}", .{self.perm_other}); |
| 1398 | } |
| 1399 | |
| 1400 | pub fn nprint(self: Mode, writer: anytype) !void { |
| 1401 | try self.type.nprint(writer); |
| 1402 | try self.perm_user.nprint(writer); |
| 1403 | try self.perm_group.nprint(writer); |
| 1404 | try self.perm_other.nprint(writer); |
| 1405 | } |
| 1406 | |
| 1407 | pub fn eql(self: Mode, other: Mode) bool { |
| 1408 | if (self.type != other.type) return false; |
| 1409 | if (self.perm_user != other.perm_user) return false; |
| 1410 | if (self.perm_group != other.perm_group) return false; |
| 1411 | if (self.perm_other != other.perm_other) return false; |
| 1412 | return true; |
| 1413 | } |
| 1414 | }; |
| 1415 | |
| 1416 | pub const Type = enum(u8) { |
| 1417 | file = 100, |
| 1418 | directory = 40, |
| 1419 | submodule = 160, |
| 1420 | symlink = 120, |
| 1421 | none = 0, |
| 1422 | |
| 1423 | pub fn format(self: Type, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 1424 | _ = fmt; |
| 1425 | _ = options; |
| 1426 | try writer.writeByte(switch (self) { |
| 1427 | .file => '-', |
| 1428 | .directory => 'd', |
| 1429 | .submodule => 'm', |
| 1430 | .symlink => '-', |
| 1431 | .none => '-', |
| 1432 | }); |
| 1433 | } |
| 1434 | |
| 1435 | pub fn nprint(self: Type, writer: anytype) !void { |
| 1436 | try writer.writeAll(&.{switch (self) { |
| 1437 | .file => '-', |
| 1438 | .directory => 'd', |
| 1439 | .submodule => 'm', |
| 1440 | .symlink => '-', |
| 1441 | .none => '-', |
| 1442 | }}); |
| 1443 | } |
| 1444 | }; |
| 1445 | |
| 1446 | pub const Perm = packed struct(u3) { |
| 1447 | execute: bool, |
| 1448 | write: bool, |
| 1449 | read: bool, |
| 1450 | |
| 1451 | pub fn format(self: Perm, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 1452 | _ = fmt; |
| 1453 | _ = options; |
| 1454 | try writer.writeByte(if (self.read) 'r' else '-'); |
| 1455 | try writer.writeByte(if (self.write) 'w' else '-'); |
| 1456 | try writer.writeByte(if (self.execute) 'x' else '-'); |
| 1457 | } |
| 1458 | |
| 1459 | pub fn nprint(self: Perm, writer: anytype) !void { |
| 1460 | try writer.writeAll(&.{ |
| 1461 | if (self.read) 'r' else '-', |
| 1462 | if (self.write) 'w' else '-', |
| 1463 | if (self.execute) 'x' else '-', |
| 1464 | }); |
| 1465 | } |
| 1466 | }; |
| 1467 | }; |
| 1468 | }; |
| 1469 | |
| 1470 | pub const Commit = struct { |
| 1471 | tree: TreeId, |
| 1472 | parents: []const CommitId, |
| 1473 | author: UserAndAt, |
| 1474 | committer: UserAndAt, |
| 1475 | message: string, |
| 1476 | }; |
| 1477 | |
| 1478 | pub const UserAndAt = struct { |
| 1479 | name: string, |
| 1480 | email: string, |
| 1481 | at: time.DateTime, |
| 1482 | }; |
| 1483 | |
| 1484 | pub const Tag = struct { |
| 1485 | object: Id, |
| 1486 | type: RefType, |
| 1487 | tagger: ?UserAndAt, |
| 1488 | message: string, |
| 1489 | }; |
| 1490 | |
| 1491 | pub const Ref = struct { |
| 1492 | oid: Id, |
| 1493 | label: string, |
| 1494 | }; |
| 1495 | |
| 1496 | 1496 | /// Variant on std.MultiArrayList but using an allocation per-field rather than a single for the entire structure. |
| 1497 | 1497 | fn MultiArrayList(T: type) type { |
| 1498 | 1498 | return struct { |