Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4499319
lockfile.zig
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
lockfile.zig
View Options
const
std
=
@import
(
"std"
);
const
builtin
=
@import
(
"builtin"
);
pub
const
MAGIC
:
u32
=
0x504B474C
;
pub
const
VERSION
:
u32
=
1
;
pub
const
StringRef
=
extern
struct
{
offset
:
u32
,
len
:
u32
,
pub
fn
slice
(
self
:
StringRef
,
string_table
:
[]
const
u8
)
[]
const
u8
{
const
offset
:
usize
=
self
.
offset
;
const
len
:
usize
=
self
.
len
;
if
(
offset
>=
string_table
.
len
)
return
""
;
const
end
=
@min
(
offset
+
len
,
string_table
.
len
);
return
string_table
[
offset
..
end
];
}
pub
const
empty
:
StringRef
=
.{
.
offset
=
0
,
.
len
=
0
};
};
pub
const
Header
=
extern
struct
{
magic
:
u32
=
MAGIC
,
version
:
u32
=
VERSION
,
package_count
:
u32
=
0
,
dependency_count
:
u32
=
0
,
string_table_offset
:
u32
=
0
,
string_table_size
:
u32
=
0
,
package_array_offset
:
u32
=
0
,
dependency_array_offset
:
u32
=
0
,
hash_table_offset
:
u32
=
0
,
hash_table_size
:
u32
=
0
,
_reserved
:
[
24
]
u8
=
[
_
]
u8
{
0
}
**
24
,
pub
fn
validate
(
self
:
*
const
Header
)
bool
{
return
self
.
magic
==
MAGIC
and
self
.
version
==
VERSION
;
}
};
pub
const
PackageFlags
=
packed
struct
(
u8
)
{
dev
:
bool
=
false
,
optional
:
bool
=
false
,
peer
:
bool
=
false
,
bundled
:
bool
=
false
,
has_bin
:
bool
=
false
,
has_scripts
:
bool
=
false
,
direct
:
bool
=
false
,
_reserved
:
u1
=
0
,
};
pub
const
Package
=
extern
struct
{
name
:
StringRef
,
version_major
:
u64
,
version_minor
:
u64
,
version_patch
:
u64
,
prerelease
:
StringRef
,
integrity
:
[
64
]
u8
,
tarball_url
:
StringRef
,
parent_path
:
StringRef
,
deps_start
:
u32
,
deps_count
:
u32
,
flags
:
PackageFlags
,
_padding
:
[
3
]
u8
=
.{
0
,
0
,
0
},
comptime
{
std
.
debug
.
assert
(
@sizeOf
(
Package
)
==
136
);
}
pub
fn
versionString
(
self
:
*
const
Package
,
allocator
:
std
.
mem
.
Allocator
,
string_table
:
[]
const
u8
)
!
[]
u8
{
const
prerelease_str
=
self
.
prerelease
.
slice
(
string_table
);
if
(
prerelease_str
.
len
>
0
)
{
return
std
.
fmt
.
allocPrint
(
allocator
,
"{d}.{d}.{d}-{s}"
,
.{
self
.
version_major
,
self
.
version_minor
,
self
.
version_patch
,
prerelease_str
,
});
}
return
std
.
fmt
.
allocPrint
(
allocator
,
"{d}.{d}.{d}"
,
.{
self
.
version_major
,
self
.
version_minor
,
self
.
version_patch
,
});
}
pub
fn
integrityHex
(
self
:
*
const
Package
)
[
128
]
u8
{
return
std
.
fmt
.
bytesToHex
(
self
.
integrity
,
.
lower
);
}
pub
fn
installPath
(
self
:
*
const
Package
,
allocator
:
std
.
mem
.
Allocator
,
string_table
:
[]
const
u8
)
!
[]
u8
{
const
parent
=
self
.
parent_path
.
slice
(
string_table
);
const
name
=
self
.
name
.
slice
(
string_table
);
if
(
parent
.
len
>
0
)
return
std
.
fmt
.
allocPrint
(
allocator
,
"{s}/node_modules/{s}"
,
.{
parent
,
name
});
return
allocator
.
dupe
(
u8
,
name
);
}
pub
fn
isNested
(
self
:
*
const
Package
)
bool
{
return
self
.
parent_path
.
len
>
0
;
}
};
pub
const
DependencyFlags
=
packed
struct
(
u8
)
{
peer
:
bool
=
false
,
dev
:
bool
=
false
,
optional
:
bool
=
false
,
_reserved
:
u5
=
0
,
};
pub
const
Dependency
=
extern
struct
{
package_index
:
u32
,
constraint
:
StringRef
,
flags
:
DependencyFlags
=
.{},
_padding
:
[
3
]
u8
=
.{
0
,
0
,
0
},
};
pub
const
HashBucket
=
extern
struct
{
name_hash
:
u32
,
package_index
:
u32
,
pub
const
empty
:
HashBucket
=
.{
.
name_hash
=
0
,
.
package_index
=
std
.
math
.
maxInt
(
u32
)
};
};
pub
fn
djb2Hash
(
str
:
[]
const
u8
)
u32
{
var
hash
:
u32
=
5381
;
for
(
str
)
|
c
|
hash
=
((
hash
<<
5
)
+%
hash
)
+%
c
;
return
hash
;
}
pub
const
Lockfile
=
struct
{
data
:
if
(
builtin
.
os
.
tag
==
.
windows
)
[]
align
(
@alignOf
(
Header
))
u8
else
[]
align
(
std
.
heap
.
page_size_min
)
const
u8
,
header
:
*
const
Header
,
string_table
:
[]
const
u8
,
packages
:
[]
const
Package
,
dependencies
:
[]
const
Dependency
,
hash_table
:
[]
const
HashBucket
,
pub
fn
open
(
path
:
[]
const
u8
)
!
Lockfile
{
const
file
=
try
std
.
fs
.
cwd
().
openFile
(
path
,
.{});
defer
file
.
close
();
const
stat
=
try
file
.
stat
();
if
(
stat
.
size
<
@sizeOf
(
Header
))
{
return
error
.
InvalidLockfile
;
}
if
(
comptime
builtin
.
os
.
tag
==
.
windows
)
{
const
data
=
try
std
.
heap
.
c_allocator
.
alignedAlloc
(
u8
,
std
.
mem
.
Alignment
.
fromByteUnits
(
@alignOf
(
Header
)),
stat
.
size
);
errdefer
std
.
heap
.
c_allocator
.
free
(
data
);
const
bytes_read
=
try
file
.
readAll
(
data
);
if
(
bytes_read
!=
stat
.
size
)
{
std
.
heap
.
c_allocator
.
free
(
data
);
return
error
.
InvalidLockfile
;
}
return
initFromDataWindows
(
data
);
}
else
{
const
data
=
try
std
.
posix
.
mmap
(
null
,
stat
.
size
,
std
.
posix
.
PROT
.
READ
,
.{
.
TYPE
=
.
PRIVATE
},
file
.
handle
,
0
,
);
return
initFromData
(
data
);
}
}
fn
initFromDataWindows
(
data
:
[]
align
(
@alignOf
(
Header
))
u8
)
!
Lockfile
{
if
(
data
.
len
<
@sizeOf
(
Header
))
return
error
.
InvalidLockfile
;
const
header
:
*
const
Header
=
@ptrCast
(
@alignCast
(
data
.
ptr
));
if
(
!
header
.
validate
())
return
error
.
InvalidLockfile
;
if
(
header
.
string_table_offset
+
header
.
string_table_size
>
data
.
len
or
header
.
package_array_offset
+
header
.
package_count
*
@sizeOf
(
Package
)
>
data
.
len
or
header
.
dependency_array_offset
+
header
.
dependency_count
*
@sizeOf
(
Dependency
)
>
data
.
len
or
header
.
hash_table_offset
+
header
.
hash_table_size
*
@sizeOf
(
HashBucket
)
>
data
.
len
)
{
return
error
.
InvalidLockfile
;
}
return
.{
.
data
=
data
,
.
header
=
header
,
.
string_table
=
data
[
header
.
string_table_offset
..][
0
..
header
.
string_table_size
],
.
packages
=
@as
([
*
]
const
Package
,
@ptrCast
(
@alignCast
(
data
.
ptr
+
header
.
package_array_offset
)))[
0
..
header
.
package_count
],
.
dependencies
=
@as
([
*
]
const
Dependency
,
@ptrCast
(
@alignCast
(
data
.
ptr
+
header
.
dependency_array_offset
)))[
0
..
header
.
dependency_count
],
.
hash_table
=
@as
([
*
]
const
HashBucket
,
@ptrCast
(
@alignCast
(
data
.
ptr
+
header
.
hash_table_offset
)))[
0
..
header
.
hash_table_size
],
};
}
pub
fn
initFromData
(
data
:
[]
align
(
std
.
heap
.
page_size_min
)
const
u8
)
!
Lockfile
{
if
(
data
.
len
<
@sizeOf
(
Header
))
{
return
error
.
InvalidLockfile
;
}
const
header
:
*
const
Header
=
@ptrCast
(
@alignCast
(
data
.
ptr
));
if
(
!
header
.
validate
())
{
return
error
.
InvalidLockfile
;
}
if
(
header
.
string_table_offset
+
header
.
string_table_size
>
data
.
len
or
header
.
package_array_offset
+
header
.
package_count
*
@sizeOf
(
Package
)
>
data
.
len
or
header
.
dependency_array_offset
+
header
.
dependency_count
*
@sizeOf
(
Dependency
)
>
data
.
len
or
header
.
hash_table_offset
+
header
.
hash_table_size
*
@sizeOf
(
HashBucket
)
>
data
.
len
)
{
return
error
.
InvalidLockfile
;
}
const
string_table
=
data
[
header
.
string_table_offset
..][
0
..
header
.
string_table_size
];
const
packages_ptr
:
[
*
]
const
Package
=
@ptrCast
(
@alignCast
(
data
.
ptr
+
header
.
package_array_offset
));
const
packages
=
packages_ptr
[
0
..
header
.
package_count
];
const
deps_ptr
:
[
*
]
const
Dependency
=
@ptrCast
(
@alignCast
(
data
.
ptr
+
header
.
dependency_array_offset
));
const
dependencies
=
deps_ptr
[
0
..
header
.
dependency_count
];
const
hash_ptr
:
[
*
]
const
HashBucket
=
@ptrCast
(
@alignCast
(
data
.
ptr
+
header
.
hash_table_offset
));
const
hash_table
=
hash_ptr
[
0
..
header
.
hash_table_size
];
return
.{
.
data
=
data
,
.
header
=
header
,
.
string_table
=
string_table
,
.
packages
=
packages
,
.
dependencies
=
dependencies
,
.
hash_table
=
hash_table
,
};
}
pub
fn
close
(
self
:
*
Lockfile
)
void
{
if
(
comptime
builtin
.
os
.
tag
==
.
windows
)
{
std
.
heap
.
c_allocator
.
free
(
self
.
data
);
}
else
std
.
posix
.
munmap
(
self
.
data
);
self
.
*
=
undefined
;
}
pub
fn
lookupPackage
(
self
:
*
const
Lockfile
,
name
:
[]
const
u8
)
?*
const
Package
{
if
(
self
.
hash_table
.
len
==
0
)
return
null
;
const
hash
=
djb2Hash
(
name
);
var
index
=
hash
%
@as
(
u32
,
@intCast
(
self
.
hash_table
.
len
));
var
probes
:
u32
=
0
;
while
(
probes
<
self
.
hash_table
.
len
)
:
(
probes
+=
1
)
{
const
bucket
=
&
self
.
hash_table
[
index
];
if
(
bucket
.
package_index
==
std
.
math
.
maxInt
(
u32
))
return
null
;
if
(
bucket
.
name_hash
==
hash
)
{
const
pkg
=
&
self
.
packages
[
bucket
.
package_index
];
const
pkg_name
=
pkg
.
name
.
slice
(
self
.
string_table
);
if
(
std
.
mem
.
eql
(
u8
,
pkg_name
,
name
))
return
pkg
;
}
index
=
(
index
+
1
)
%
@as
(
u32
,
@intCast
(
self
.
hash_table
.
len
));
}
return
null
;
}
pub
fn
getPackageDeps
(
self
:
*
const
Lockfile
,
pkg
:
*
const
Package
)
[]
const
Dependency
{
if
(
pkg
.
deps_count
==
0
)
return
&
[
_
]
Dependency
{};
if
(
pkg
.
deps_start
>=
self
.
dependencies
.
len
or
pkg
.
deps_start
+
pkg
.
deps_count
>
self
.
dependencies
.
len
)
return
&
[
_
]
Dependency
{};
return
self
.
dependencies
[
pkg
.
deps_start
..][
0
..
pkg
.
deps_count
];
}
};
pub
const
LockfileWriter
=
struct
{
allocator
:
std
.
mem
.
Allocator
,
packages
:
std
.
ArrayListUnmanaged
(
Package
),
dependencies
:
std
.
ArrayListUnmanaged
(
Dependency
),
string_builder
:
std
.
ArrayListUnmanaged
(
u8
),
string_offsets
:
std
.
StringHashMap
(
StringRef
),
pub
fn
init
(
allocator
:
std
.
mem
.
Allocator
)
LockfileWriter
{
return
.{
.
allocator
=
allocator
,
.
packages
=
.{},
.
dependencies
=
.{},
.
string_builder
=
.{},
.
string_offsets
=
std
.
StringHashMap
(
StringRef
).
init
(
allocator
),
};
}
pub
fn
deinit
(
self
:
*
LockfileWriter
)
void
{
self
.
packages
.
deinit
(
self
.
allocator
);
self
.
dependencies
.
deinit
(
self
.
allocator
);
self
.
string_builder
.
deinit
(
self
.
allocator
);
var
key_iter
=
self
.
string_offsets
.
keyIterator
();
while
(
key_iter
.
next
())
|
key
|
{
self
.
allocator
.
free
(
key
.
*
);
}
self
.
string_offsets
.
deinit
();
}
pub
fn
internString
(
self
:
*
LockfileWriter
,
str
:
[]
const
u8
)
!
StringRef
{
if
(
str
.
len
==
0
)
return
StringRef
.
empty
;
if
(
self
.
string_offsets
.
get
(
str
))
|
ref
|
return
ref
;
if
(
self
.
string_builder
.
items
.
len
>
std
.
math
.
maxInt
(
u32
))
return
error
.
StringTableTooLarge
;
if
(
str
.
len
>
std
.
math
.
maxInt
(
u32
))
return
error
.
StringTooLarge
;
const
offset
:
u32
=
@intCast
(
self
.
string_builder
.
items
.
len
);
try
self
.
string_builder
.
appendSlice
(
self
.
allocator
,
str
);
const
ref
=
StringRef
{
.
offset
=
offset
,
.
len
=
@intCast
(
str
.
len
)
};
const
stored_str
=
try
self
.
allocator
.
dupe
(
u8
,
str
);
errdefer
self
.
allocator
.
free
(
stored_str
);
try
self
.
string_offsets
.
put
(
stored_str
,
ref
);
return
ref
;
}
pub
fn
addPackage
(
self
:
*
LockfileWriter
,
pkg
:
Package
)
!
u32
{
const
index
:
u32
=
@intCast
(
self
.
packages
.
items
.
len
);
try
self
.
packages
.
append
(
self
.
allocator
,
pkg
);
return
index
;
}
pub
fn
addDependency
(
self
:
*
LockfileWriter
,
dep
:
Dependency
)
!
void
{
try
self
.
dependencies
.
append
(
self
.
allocator
,
dep
);
}
fn
alignOffset
(
offset
:
u32
,
alignment
:
u32
)
u32
{
const
rem
=
offset
%
alignment
;
return
if
(
rem
==
0
)
offset
else
offset
+
(
alignment
-
rem
);
}
pub
fn
write
(
self
:
*
LockfileWriter
,
path
:
[]
const
u8
)
!
void
{
const
file
=
try
std
.
fs
.
cwd
().
createFile
(
path
,
.{});
defer
file
.
close
();
const
header_size
:
u32
=
@sizeOf
(
Header
);
const
string_table_offset
=
header_size
;
const
string_table_size
:
u32
=
@intCast
(
self
.
string_builder
.
items
.
len
);
const
package_array_offset
=
alignOffset
(
string_table_offset
+
string_table_size
,
@alignOf
(
Package
));
const
package_pad_size
=
package_array_offset
-
(
string_table_offset
+
string_table_size
);
const
package_array_size
:
u32
=
@intCast
(
self
.
packages
.
items
.
len
*
@sizeOf
(
Package
));
const
dependency_array_offset
=
alignOffset
(
package_array_offset
+
package_array_size
,
@alignOf
(
Dependency
));
const
dep_pad_size
=
dependency_array_offset
-
(
package_array_offset
+
package_array_size
);
const
dependency_array_size
:
u32
=
@intCast
(
self
.
dependencies
.
items
.
len
*
@sizeOf
(
Dependency
));
const
hash_table_size
:
u32
=
@intCast
(
@max
(
1
,
self
.
packages
.
items
.
len
*
10
/
7
));
var
hash_table
=
try
self
.
allocator
.
alloc
(
HashBucket
,
hash_table_size
);
defer
self
.
allocator
.
free
(
hash_table
);
for
(
hash_table
)
|*
bucket
|
{
bucket
.
*
=
HashBucket
.
empty
;
}
for
(
self
.
packages
.
items
,
0
..)
|
pkg
,
i
|
{
const
name
=
pkg
.
name
.
slice
(
self
.
string_builder
.
items
);
const
hash
=
djb2Hash
(
name
);
var
index
=
hash
%
hash_table_size
;
var
probes
:
u32
=
0
;
while
(
hash_table
[
index
].
package_index
!=
std
.
math
.
maxInt
(
u32
)
and
probes
<
hash_table_size
)
:
(
probes
+=
1
)
{
index
=
(
index
+
1
)
%
hash_table_size
;
}
if
(
probes
>=
hash_table_size
)
return
error
.
HashTableFull
;
hash_table
[
index
]
=
.{
.
name_hash
=
hash
,
.
package_index
=
@intCast
(
i
),
};
}
const
hash_table_offset
=
alignOffset
(
dependency_array_offset
+
dependency_array_size
,
@alignOf
(
HashBucket
));
const
hash_pad_size
=
hash_table_offset
-
(
dependency_array_offset
+
dependency_array_size
);
const
header
=
Header
{
.
package_count
=
@intCast
(
self
.
packages
.
items
.
len
),
.
dependency_count
=
@intCast
(
self
.
dependencies
.
items
.
len
),
.
string_table_offset
=
string_table_offset
,
.
string_table_size
=
string_table_size
,
.
package_array_offset
=
package_array_offset
,
.
dependency_array_offset
=
dependency_array_offset
,
.
hash_table_offset
=
hash_table_offset
,
.
hash_table_size
=
hash_table_size
,
};
try
file
.
writeAll
(
std
.
mem
.
asBytes
(
&
header
));
try
file
.
writeAll
(
self
.
string_builder
.
items
);
if
(
package_pad_size
>
0
)
{
const
padding
=
[
_
]
u8
{
0
}
**
8
;
try
file
.
writeAll
(
padding
[
0
..
package_pad_size
]);
}
try
file
.
writeAll
(
std
.
mem
.
sliceAsBytes
(
self
.
packages
.
items
));
if
(
dep_pad_size
>
0
)
{
const
padding
=
[
_
]
u8
{
0
}
**
8
;
try
file
.
writeAll
(
padding
[
0
..
dep_pad_size
]);
}
try
file
.
writeAll
(
std
.
mem
.
sliceAsBytes
(
self
.
dependencies
.
items
));
if
(
hash_pad_size
>
0
)
{
const
padding
=
[
_
]
u8
{
0
}
**
8
;
try
file
.
writeAll
(
padding
[
0
..
hash_pad_size
]);
}
try
file
.
writeAll
(
std
.
mem
.
sliceAsBytes
(
hash_table
));
}
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, May 3, 7:58 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
533615
Default Alt Text
lockfile.zig (13 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment