swhid 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +37 -2
- data/exe/swhid +153 -5
- data/lib/swhid/from_git.rb +135 -0
- data/lib/swhid/objects/directory.rb +4 -1
- data/lib/swhid/version.rb +1 -1
- data/lib/swhid.rb +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 17e5d6a13e7f6d44bed90224e6ff6b1418bd9501b7bd14c1ef00d5d7adbbeb3c
|
|
4
|
+
data.tar.gz: 712d0c4136e0ac2c5d11b38b73cbf77d75bbf87b188fc998a3f716e4f9e8ff98
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7fa9985d872d26ade840cdb509319fe27795dbd7bbac18b9a4141eb291dcee55cdeb5be31ad94a2fd557b2d676124016c955303bee9a7b4dac1ff698fc22ddc9
|
|
7
|
+
data.tar.gz: e99b1253233fd0862a7b57da14ca6367036e5cb50b4d153ffe154165be2635bf8f7579a5a8d3ae10757972dfc511d591c9485bf66cca001db8336b5dc08d4349
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.3.0] - 2025-11-23
|
|
4
|
+
|
|
5
|
+
- `directory` CLI command - Generate SWHID for directory from filesystem
|
|
6
|
+
- `revision` CLI command - Generate SWHID for git commit/revision
|
|
7
|
+
- `release` CLI command - Generate SWHID for git tag/release
|
|
8
|
+
- `snapshot` CLI command - Generate SWHID for git repository snapshot
|
|
9
|
+
|
|
3
10
|
## [0.2.1] - 2025-11-09
|
|
4
11
|
|
|
5
12
|
- Package manager tests for PyPI, RubyGems, Maven, Cargo, and NPM artifacts (content and extracted directories)
|
data/README.md
CHANGED
|
@@ -151,12 +151,13 @@ swhid = Swhid::Identifier.new(
|
|
|
151
151
|
visit: "swh:1:snp:d7f1b9eb7ccb596c2622c4780febaa02549830f9",
|
|
152
152
|
anchor: "swh:1:rev:2db189928c94d62a3b4757b3eec68f0a4d4113f0",
|
|
153
153
|
path: "/src/main.rb",
|
|
154
|
-
lines: "10-20"
|
|
154
|
+
lines: "10-20",
|
|
155
|
+
bytes: "0-100"
|
|
155
156
|
}
|
|
156
157
|
)
|
|
157
158
|
|
|
158
159
|
puts swhid.to_s
|
|
159
|
-
# => "swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2;origin=https://github.com/example/repo;visit=swh:1:snp:...;anchor=swh:1:rev:...;path=/src/main.rb;lines=10-20"
|
|
160
|
+
# => "swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2;origin=https://github.com/example/repo;visit=swh:1:snp:...;anchor=swh:1:rev:...;path=/src/main.rb;lines=10-20;bytes=0-100"
|
|
160
161
|
```
|
|
161
162
|
|
|
162
163
|
### CLI Usage
|
|
@@ -183,6 +184,40 @@ $ echo "Hello, World!" | swhid content
|
|
|
183
184
|
swh:1:cnt:96898574d1b88e619be24fd90bb4cd399acbc5ca
|
|
184
185
|
```
|
|
185
186
|
|
|
187
|
+
**Generate SWHID from directory**
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
$ swhid directory /path/to/directory
|
|
191
|
+
swh:1:dir:4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Generate SWHID from git commit**
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
$ swhid revision /path/to/repo
|
|
198
|
+
swh:1:rev:bc0195aad0daa2ad5b0d76cce22b167bc3435590
|
|
199
|
+
|
|
200
|
+
$ swhid revision /path/to/repo main
|
|
201
|
+
swh:1:rev:bc0195aad0daa2ad5b0d76cce22b167bc3435590
|
|
202
|
+
|
|
203
|
+
$ swhid revision /path/to/repo abc123
|
|
204
|
+
swh:1:rev:bc0195aad0daa2ad5b0d76cce22b167bc3435590
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Generate SWHID from git tag**
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
$ swhid release /path/to/repo v1.0.0
|
|
211
|
+
swh:1:rel:2b10839e32c4c476e9d94492756bb1a3e1ec4aa8
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Generate SWHID from git snapshot**
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
$ swhid snapshot /path/to/repo
|
|
218
|
+
swh:1:snp:6e65b86363953b780d92b0a928f3e8fcdd10db36
|
|
219
|
+
```
|
|
220
|
+
|
|
186
221
|
**Add qualifiers**
|
|
187
222
|
|
|
188
223
|
```bash
|
data/exe/swhid
CHANGED
|
@@ -24,6 +24,14 @@ class SwhidCLI
|
|
|
24
24
|
parse_swhid
|
|
25
25
|
when "content"
|
|
26
26
|
compute_content_swhid
|
|
27
|
+
when "directory"
|
|
28
|
+
compute_directory_swhid
|
|
29
|
+
when "revision"
|
|
30
|
+
compute_revision_swhid
|
|
31
|
+
when "release"
|
|
32
|
+
compute_release_swhid
|
|
33
|
+
when "snapshot"
|
|
34
|
+
compute_snapshot_swhid
|
|
27
35
|
when "help"
|
|
28
36
|
show_help
|
|
29
37
|
else
|
|
@@ -41,9 +49,13 @@ class SwhidCLI
|
|
|
41
49
|
opts.banner = "Usage: swhid [command] [options]"
|
|
42
50
|
opts.separator ""
|
|
43
51
|
opts.separator "Commands:"
|
|
44
|
-
opts.separator " parse <swhid>
|
|
45
|
-
opts.separator " content
|
|
46
|
-
opts.separator "
|
|
52
|
+
opts.separator " parse <swhid> Parse and validate a SWHID"
|
|
53
|
+
opts.separator " content Generate SWHID for content from stdin"
|
|
54
|
+
opts.separator " directory <path> Generate SWHID for directory"
|
|
55
|
+
opts.separator " revision <repo> [ref] Generate SWHID for git revision/commit"
|
|
56
|
+
opts.separator " release <repo> <tag> Generate SWHID for git release/tag"
|
|
57
|
+
opts.separator " snapshot <repo> Generate SWHID for git snapshot"
|
|
58
|
+
opts.separator " help Show this help message"
|
|
47
59
|
opts.separator ""
|
|
48
60
|
opts.separator "Options:"
|
|
49
61
|
|
|
@@ -104,6 +116,124 @@ class SwhidCLI
|
|
|
104
116
|
end
|
|
105
117
|
end
|
|
106
118
|
|
|
119
|
+
def compute_directory_swhid
|
|
120
|
+
path = @args.shift
|
|
121
|
+
unless path
|
|
122
|
+
puts "Error: Directory path required"
|
|
123
|
+
exit 1
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
unless File.exist?(path)
|
|
127
|
+
puts "Error: Path does not exist: #{path}"
|
|
128
|
+
exit 1
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
unless File.directory?(path)
|
|
132
|
+
puts "Error: Path is not a directory: #{path}"
|
|
133
|
+
exit 1
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
swhid = Swhid::FromFilesystem.from_directory_path(path)
|
|
137
|
+
|
|
138
|
+
unless @options[:qualifiers].empty?
|
|
139
|
+
swhid = Swhid::Identifier.new(
|
|
140
|
+
object_type: swhid.object_type,
|
|
141
|
+
object_hash: swhid.object_hash,
|
|
142
|
+
qualifiers: @options[:qualifiers]
|
|
143
|
+
)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
case @options[:format]
|
|
147
|
+
when "json"
|
|
148
|
+
output_json(swhid)
|
|
149
|
+
else
|
|
150
|
+
puts swhid.to_s
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def compute_revision_swhid
|
|
155
|
+
repo_path = @args.shift
|
|
156
|
+
unless repo_path
|
|
157
|
+
puts "Error: Repository path required"
|
|
158
|
+
exit 1
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
ref = @args.shift || "HEAD"
|
|
162
|
+
|
|
163
|
+
swhid = Swhid::FromGit.from_revision(repo_path, ref)
|
|
164
|
+
|
|
165
|
+
unless @options[:qualifiers].empty?
|
|
166
|
+
swhid = Swhid::Identifier.new(
|
|
167
|
+
object_type: swhid.object_type,
|
|
168
|
+
object_hash: swhid.object_hash,
|
|
169
|
+
qualifiers: @options[:qualifiers]
|
|
170
|
+
)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
case @options[:format]
|
|
174
|
+
when "json"
|
|
175
|
+
output_json(swhid)
|
|
176
|
+
else
|
|
177
|
+
puts swhid.to_s
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def compute_release_swhid
|
|
182
|
+
repo_path = @args.shift
|
|
183
|
+
unless repo_path
|
|
184
|
+
puts "Error: Repository path required"
|
|
185
|
+
exit 1
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
tag_name = @args.shift
|
|
189
|
+
unless tag_name
|
|
190
|
+
puts "Error: Tag name required"
|
|
191
|
+
exit 1
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
swhid = Swhid::FromGit.from_release(repo_path, tag_name)
|
|
195
|
+
|
|
196
|
+
unless @options[:qualifiers].empty?
|
|
197
|
+
swhid = Swhid::Identifier.new(
|
|
198
|
+
object_type: swhid.object_type,
|
|
199
|
+
object_hash: swhid.object_hash,
|
|
200
|
+
qualifiers: @options[:qualifiers]
|
|
201
|
+
)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
case @options[:format]
|
|
205
|
+
when "json"
|
|
206
|
+
output_json(swhid)
|
|
207
|
+
else
|
|
208
|
+
puts swhid.to_s
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def compute_snapshot_swhid
|
|
213
|
+
repo_path = @args.shift
|
|
214
|
+
unless repo_path
|
|
215
|
+
puts "Error: Repository path required"
|
|
216
|
+
exit 1
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
swhid = Swhid::FromGit.from_snapshot(repo_path)
|
|
220
|
+
|
|
221
|
+
unless @options[:qualifiers].empty?
|
|
222
|
+
swhid = Swhid::Identifier.new(
|
|
223
|
+
object_type: swhid.object_type,
|
|
224
|
+
object_hash: swhid.object_hash,
|
|
225
|
+
qualifiers: @options[:qualifiers]
|
|
226
|
+
)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
case @options[:format]
|
|
230
|
+
when "json"
|
|
231
|
+
output_json(swhid)
|
|
232
|
+
else
|
|
233
|
+
puts swhid.to_s
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
107
237
|
def output_text(swhid)
|
|
108
238
|
puts "SWHID: #{swhid.to_s}"
|
|
109
239
|
puts "Core: #{swhid.core_swhid}"
|
|
@@ -134,8 +264,12 @@ class SwhidCLI
|
|
|
134
264
|
swhid - Generate and parse SoftWare Hash IDentifiers
|
|
135
265
|
|
|
136
266
|
Usage:
|
|
137
|
-
swhid parse <swhid>
|
|
138
|
-
swhid content [options]
|
|
267
|
+
swhid parse <swhid> Parse and validate a SWHID
|
|
268
|
+
swhid content [options] Generate SWHID for content from stdin
|
|
269
|
+
swhid directory <path> [options] Generate SWHID for directory
|
|
270
|
+
swhid revision <repo> [ref] [options] Generate SWHID for git revision/commit
|
|
271
|
+
swhid release <repo> <tag> [options] Generate SWHID for git release/tag
|
|
272
|
+
swhid snapshot <repo> [options] Generate SWHID for git snapshot
|
|
139
273
|
|
|
140
274
|
Options:
|
|
141
275
|
-f, --format FORMAT Output format (text, json)
|
|
@@ -149,6 +283,20 @@ class SwhidCLI
|
|
|
149
283
|
# Generate SWHID from file content
|
|
150
284
|
cat file.txt | swhid content
|
|
151
285
|
|
|
286
|
+
# Generate SWHID from directory
|
|
287
|
+
swhid directory /path/to/dir
|
|
288
|
+
|
|
289
|
+
# Generate SWHID from git commit
|
|
290
|
+
swhid revision /path/to/repo
|
|
291
|
+
swhid revision /path/to/repo main
|
|
292
|
+
swhid revision /path/to/repo abc123
|
|
293
|
+
|
|
294
|
+
# Generate SWHID from git tag
|
|
295
|
+
swhid release /path/to/repo v1.0.0
|
|
296
|
+
|
|
297
|
+
# Generate SWHID from git snapshot
|
|
298
|
+
swhid snapshot /path/to/repo
|
|
299
|
+
|
|
152
300
|
# Generate SWHID with qualifiers
|
|
153
301
|
cat file.txt | swhid content -q origin=https://github.com/example/repo
|
|
154
302
|
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rugged"
|
|
4
|
+
|
|
5
|
+
module Swhid
|
|
6
|
+
module FromGit
|
|
7
|
+
def self.from_revision(repo_path, ref = "HEAD")
|
|
8
|
+
repo = Rugged::Repository.new(repo_path)
|
|
9
|
+
commit = repo.rev_parse(ref)
|
|
10
|
+
|
|
11
|
+
raise ArgumentError, "Reference #{ref} is not a commit" unless commit.is_a?(Rugged::Commit)
|
|
12
|
+
|
|
13
|
+
metadata = {
|
|
14
|
+
directory: commit.tree.oid,
|
|
15
|
+
parents: commit.parents.map(&:oid),
|
|
16
|
+
author: format_person(commit.author),
|
|
17
|
+
author_timestamp: commit.author[:time].to_i,
|
|
18
|
+
author_timezone: format_timezone(commit.author[:time]),
|
|
19
|
+
committer: format_person(commit.committer),
|
|
20
|
+
committer_timestamp: commit.committer[:time].to_i,
|
|
21
|
+
committer_timezone: format_timezone(commit.committer[:time]),
|
|
22
|
+
message: commit.message
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# Extract extra headers if present
|
|
26
|
+
extra_headers = extract_extra_headers(commit)
|
|
27
|
+
metadata[:extra_headers] = extra_headers unless extra_headers.empty?
|
|
28
|
+
|
|
29
|
+
Swhid.from_revision(metadata)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.from_release(repo_path, tag_name)
|
|
33
|
+
repo = Rugged::Repository.new(repo_path)
|
|
34
|
+
tag_ref = repo.references["refs/tags/#{tag_name}"]
|
|
35
|
+
|
|
36
|
+
raise ArgumentError, "Tag #{tag_name} not found" unless tag_ref
|
|
37
|
+
|
|
38
|
+
# Get the tag object
|
|
39
|
+
tag_obj = repo.lookup(tag_ref.target_id)
|
|
40
|
+
|
|
41
|
+
# Check if it's an annotated tag
|
|
42
|
+
if tag_obj.is_a?(Rugged::Tag::Annotation)
|
|
43
|
+
target_type = case tag_obj.target
|
|
44
|
+
when Rugged::Commit then "rev"
|
|
45
|
+
when Rugged::Tree then "dir"
|
|
46
|
+
when Rugged::Blob then "cnt"
|
|
47
|
+
else "rev"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
metadata = {
|
|
51
|
+
name: tag_obj.name,
|
|
52
|
+
target: { hash: tag_obj.target.oid, type: target_type },
|
|
53
|
+
message: tag_obj.message
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if tag_obj.tagger
|
|
57
|
+
metadata[:author] = format_person(tag_obj.tagger)
|
|
58
|
+
metadata[:author_timestamp] = tag_obj.tagger[:time].to_i
|
|
59
|
+
metadata[:author_timezone] = format_timezone(tag_obj.tagger[:time])
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
Swhid.from_release(metadata)
|
|
63
|
+
else
|
|
64
|
+
# Lightweight tag - points directly to commit
|
|
65
|
+
raise ArgumentError, "Lightweight tags are not supported for release SWHIDs"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.from_snapshot(repo_path)
|
|
70
|
+
repo = Rugged::Repository.new(repo_path)
|
|
71
|
+
branches = []
|
|
72
|
+
|
|
73
|
+
# Get all references (branches and tags)
|
|
74
|
+
repo.references.each do |ref|
|
|
75
|
+
ref_name = ref.name
|
|
76
|
+
|
|
77
|
+
if ref.type == :symbolic
|
|
78
|
+
# This is an alias (like HEAD pointing to refs/heads/main)
|
|
79
|
+
target_ref_name = ref.target
|
|
80
|
+
branches << {
|
|
81
|
+
name: ref_name,
|
|
82
|
+
target_type: "alias",
|
|
83
|
+
target: target_ref_name
|
|
84
|
+
}
|
|
85
|
+
else
|
|
86
|
+
# Direct reference
|
|
87
|
+
target_obj = ref.target
|
|
88
|
+
|
|
89
|
+
# Determine target type and OID
|
|
90
|
+
target_type, target_oid = case target_obj
|
|
91
|
+
when Rugged::Commit
|
|
92
|
+
["revision", target_obj.oid]
|
|
93
|
+
when Rugged::Tag::Annotation
|
|
94
|
+
["release", target_obj.oid]
|
|
95
|
+
when Rugged::Tree
|
|
96
|
+
["directory", target_obj.oid]
|
|
97
|
+
when Rugged::Blob
|
|
98
|
+
["content", target_obj.oid]
|
|
99
|
+
else
|
|
100
|
+
["revision", target_obj.oid]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
branches << {
|
|
104
|
+
name: ref_name,
|
|
105
|
+
target_type: target_type,
|
|
106
|
+
target: target_oid
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
Swhid.from_snapshot(branches)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def self.format_person(person)
|
|
117
|
+
"#{person[:name]} <#{person[:email]}>"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.format_timezone(time)
|
|
121
|
+
offset = time.utc_offset
|
|
122
|
+
sign = offset >= 0 ? "+" : "-"
|
|
123
|
+
hours = offset.abs / 3600
|
|
124
|
+
minutes = (offset.abs % 3600) / 60
|
|
125
|
+
format("%s%02d%02d", sign, hours, minutes)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def self.extract_extra_headers(commit)
|
|
129
|
+
# Rugged doesn't expose extra headers directly
|
|
130
|
+
# We would need to parse the raw commit object for this
|
|
131
|
+
# For now, return empty array
|
|
132
|
+
[]
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -69,7 +69,10 @@ module Swhid
|
|
|
69
69
|
sorted_entries = entries.sort_by(&:sort_key)
|
|
70
70
|
|
|
71
71
|
sorted_entries.map do |entry|
|
|
72
|
-
|
|
72
|
+
# Convert name to binary UTF-8 to match target_hash encoding
|
|
73
|
+
name_binary = entry.name.encode(Encoding::UTF_8).force_encoding(Encoding::BINARY)
|
|
74
|
+
perms_binary = entry.perms.encode(Encoding::UTF_8).force_encoding(Encoding::BINARY)
|
|
75
|
+
"#{perms_binary} #{name_binary}\0#{entry.target_hash}"
|
|
73
76
|
end.join
|
|
74
77
|
end
|
|
75
78
|
|
data/lib/swhid/version.rb
CHANGED
data/lib/swhid.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: swhid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Nesbitt
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rugged
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.9'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.9'
|
|
12
26
|
description: A Ruby library and CLI for generating and parsing SoftWare Hash IDentifiers
|
|
13
27
|
(SWHIDs). Supports all object types (content, directory, revision, release, snapshot)
|
|
14
28
|
and qualifiers. Compatible with Git object hashing.
|
|
@@ -27,6 +41,7 @@ files:
|
|
|
27
41
|
- exe/swhid
|
|
28
42
|
- lib/swhid.rb
|
|
29
43
|
- lib/swhid/from_filesystem.rb
|
|
44
|
+
- lib/swhid/from_git.rb
|
|
30
45
|
- lib/swhid/identifier.rb
|
|
31
46
|
- lib/swhid/objects/content.rb
|
|
32
47
|
- lib/swhid/objects/directory.rb
|