Skip to content

Commit d503e06

Browse files
committed
registry: Create an abstraction for registries.
1 parent 04d273f commit d503e06

File tree

9 files changed

+329
-187
lines changed

9 files changed

+329
-187
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ MAKEFILES = $(wildcard deps/*/Makefile)
2323
export CC
2424

2525
ifdef STATIC
26-
CFLAGS += -DCURL_STATICLIB -std=c99 -Ideps -Wall -Wno-unused-function -U__STRICT_ANSI__ $(shell deps/curl/bin/curl-config --cflags)
26+
CFLAGS += -DCURL_STATICLIB -std=c99 -Ideps -Wall -Werror=return-type -Wno-unused-function -U__STRICT_ANSI__ $(shell deps/curl/bin/curl-config --cflags)
2727
LDFLAGS += -static $(shell deps/curl/bin/curl-config --static-libs)
2828
else
2929
CFLAGS += -std=c99 -Ideps -Wall -Wno-unused-function -U__STRICT_ANSI__ $(shell curl-config --cflags)
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//
2+
// github-registry.c
3+
//
4+
// Copyright (c) 2020 Elbert van de Put
5+
// Based on work by Stephen Mathieson
6+
// MIT licensed
7+
//
8+
#include <string.h>
9+
#include "github-registry.h"
10+
#include "gumbo-text-content/gumbo-text-content.h"
11+
#include "gumbo-get-element-by-id/get-element-by-id.h"
12+
#include "gumbo-get-elements-by-tag-name/get-elements-by-tag-name.h"
13+
#include "http-get/http-get.h"
14+
#include <curl/curl.h>
15+
#include "substr/substr.h"
16+
#include "strdup/strdup.h"
17+
#include "case/case.h"
18+
#include "trim/trim.h"
19+
#include "wiki-registry-internal.h"
20+
21+
/**
22+
* Add `href` to the given `package`.
23+
*/
24+
static void add_package_href(wiki_package_ptr_t self) {
25+
size_t len = strlen(self->repo) + 20; // https://github.com/ \0
26+
self->href = malloc(len);
27+
if (self->href)
28+
sprintf(self->href, "https://github.com/%s", self->repo);
29+
}
30+
31+
/**
32+
* Parse the given wiki `li` into a package.
33+
*/
34+
static wiki_package_ptr_t parse_li(GumboNode *li) {
35+
wiki_package_ptr_t self = wiki_package_new();
36+
char *text = NULL;
37+
38+
if (!self) goto cleanup;
39+
40+
text = gumbo_text_content(li);
41+
if (!text) goto cleanup;
42+
43+
// TODO support unicode dashes
44+
char *tok = strstr(text, " - ");
45+
if (!tok) goto cleanup;
46+
47+
int pos = tok - text;
48+
self->repo = substr(text, 0, pos);
49+
self->description = substr(text, pos + 3, -1);
50+
if (!self->repo || !self->description) goto cleanup;
51+
trim(self->description);
52+
trim(self->repo);
53+
54+
add_package_href(self);
55+
56+
cleanup:
57+
free(text);
58+
return self;
59+
}
60+
61+
/**
62+
* Parse a list of packages from the given `html`
63+
*/
64+
list_t *wiki_registry_parse(const char *html) {
65+
GumboOutput *output = gumbo_parse(html);
66+
list_t *pkgs = list_new();
67+
68+
GumboNode *body = gumbo_get_element_by_id("wiki-body", output->root);
69+
if (body) {
70+
// grab all category `<h2 />`s
71+
list_t *h2s = gumbo_get_elements_by_tag_name("h2", body);
72+
list_node_t *heading_node;
73+
list_iterator_t *heading_iterator = list_iterator_new(h2s, LIST_HEAD);
74+
while ((heading_node = list_iterator_next(heading_iterator))) {
75+
GumboNode *heading = (GumboNode *) heading_node->val;
76+
char *category = gumbo_text_content(heading);
77+
// die if we failed to parse a category, as it's
78+
// almost certinaly a malloc error
79+
if (!category) break;
80+
trim(case_lower(category));
81+
GumboVector *siblings = &heading->parent->v.element.children;
82+
size_t pos = heading->index_within_parent;
83+
84+
// skip elements until the UL
85+
// TODO: don't hardcode position here
86+
// 2:
87+
// 1 - whitespace
88+
// 2 - actual node
89+
GumboNode *ul = siblings->data[pos + 2];
90+
if (GUMBO_TAG_UL != ul->v.element.tag) {
91+
free(category);
92+
continue;
93+
}
94+
95+
list_t *lis = gumbo_get_elements_by_tag_name("li", ul);
96+
list_iterator_t *li_iterator = list_iterator_new(lis, LIST_HEAD);
97+
list_node_t *li_node;
98+
while ((li_node = list_iterator_next(li_iterator))) {
99+
wiki_package_ptr_t package = parse_li(li_node->val);
100+
if (package && package->description) {
101+
package->category = strdup(category);
102+
list_rpush(pkgs, list_node_new(package));
103+
} else {
104+
// failed to parse package
105+
if (package) wiki_package_free(package);
106+
}
107+
}
108+
list_iterator_destroy(li_iterator);
109+
list_destroy(lis);
110+
free(category);
111+
}
112+
list_iterator_destroy(heading_iterator);
113+
list_destroy(h2s);
114+
}
115+
116+
gumbo_destroy_output(&kGumboDefaultOptions, output);
117+
return pkgs;
118+
}
119+
120+
/**
121+
* Get a list of packages from the given GitHub wiki `url`.
122+
*/
123+
list_t *github_registry_fetch(const char *url) {
124+
http_get_response_t *res = http_get(url);
125+
if (!res->ok) return NULL;
126+
127+
list_t *list = wiki_registry_parse(res->data);
128+
http_get_free(res);
129+
return list;
130+
}
131+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef CLIB_GITHUB_REGISTRY_H
2+
#define CLIB_GITHUB_REGISTRY_H
3+
4+
#include "list/list.h"
5+
6+
list_t* github_registry_fetch(const char *url);
7+
8+
#endif //CLIB_GITHUB_REGISTRY_H
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// gitlab-registry.c
3+
//
4+
// Copyright (c) 2020 Elbert van de Put
5+
// MIT licensed
6+
//
7+
#include "gitlab-registry.h"
8+
9+
list_t* gitlab_registry_fetch(const char *url) {
10+
return NULL;
11+
}
12+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef CLIB_GITLAB_REGISTRY_H
2+
#define CLIB_GITLAB_REGISTRY_H
3+
4+
#include "list/list.h"
5+
6+
list_t* gitlab_registry_fetch(const char *url);
7+
8+
#endif //CLIB_GITLAB_REGISTRY_H
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef WIKI_REGISTRY_HELPER_H
2+
#define WIKI_REGISTRY_HELPER_H
3+
// DO NOT INCLUDE. THIS HEADER IS INTERNAL ONLY
4+
#include "wiki-registry.h"
5+
6+
struct wiki_package_t {
7+
char *repo;
8+
char *href;
9+
char *description;
10+
char *category;
11+
};
12+
13+
wiki_package_ptr_t wiki_package_new();
14+
15+
void wiki_package_free(wiki_package_ptr_t pkg);
16+
17+
#endif //WIKI_REGISTRY_HELPER_H

0 commit comments

Comments
 (0)