6 use InvalidArgumentException
;
10 use function file_get_contents
;
13 use function realpath
;
21 class Repo
implements IteratorAggregate
{
23 * The name of the repository
29 * The path to the repository
35 * The edit url template
53 * Comment provider configuration
56 private $commentProvider;
59 * Path to the repository containing the name.mdref file
61 * @throws \InvalidArgumentException
63 public function __construct(string $path) {
64 if (!($glob = glob("$path/{mdref.*,*.mdref}", GLOB_BRACE
))) {
65 throw new InvalidArgumentException("Not a reference, could not find any '{mdref.*,*.mdref}': '$path'");
68 $this->path
= realpath($path);
69 foreach ($glob as $mdref) {
70 switch (pathinfo($mdref, PATHINFO_EXTENSION
)) {
72 $this->name
= basename($mdref, ".mdref");
73 $this->editUrl
= trim(file_get_contents($mdref));
76 $json = json_decode(file_get_contents($mdref));
77 if (!isset($json->name
)) {
78 throw new InvalidArgumentException("Missing key 'path' in $mdref");
80 $this->name
= $json->name
;
81 foreach (["origin", "branch", "editUrl", "commentProvider"] as $key) {
82 if (isset($json->$key)) {
83 $this->$key = $json->$key;
88 throw InvalidArgumentException("Unknown $path");
94 * Get the repository's name
97 public function getName() : string {
102 * Get the path of the repository or a file in it
103 * @param string $file
106 public function getPath(string $file = "") : string {
107 return $this->path
. "/$file";
111 * Get the edit url for a ref entry
112 * @param string $entry
115 public function getEditUrl(string $entry) : string {
116 return sprintf($this->editUrl
, $entry);
122 public function getBranch() {
123 return $this->branch
;
129 public function getOrigin() {
130 return $this->origin
;
136 public function getCommentProvider() {
137 return $this->commentProvider
;
141 * Get the file path of an entry in this repo
143 * @param string $entry
144 * @param string|null $canonical
145 * @return string file path
147 public function hasEntry(string $entry, ?
string &$canonical = null) : ?
string {
148 $trim = rtrim($entry, "/");
149 $file = $this->getPath("$trim.md");
150 if (is_file($file)) {
151 if ($trim !== $entry) {
156 $file = $this->getPath($this->getName()."/$entry.md");
157 if (is_file($file)) {
158 $canonical = $this->getName() . "/" . $entry;
165 * Get the canonical entry name of a file in this repo
166 * @param string $file
167 * @return string entry
169 public function hasFile(string $file) : ?
string {
170 if (($file = realpath($file))) {
171 $path = $this->getPath();
172 $plen = strlen($path);
173 if (!strncmp($file, $path, $plen)) {
174 $dirname = dirname(substr($file, $plen));
175 $basename = basename($file, ".md");
177 if ($dirname === ".") {
181 return $dirname . "/". $basename;
188 * Check whether the repo has a stub file to serve
189 * @param string|null $path receives the path if there's a stub
192 public function hasStub(string &$path = null) : bool {
193 $path = $this->getPath($this->getName() . ".stub.php");
194 return is_file($path) && is_readable($path);
198 * Get an Entry instance
199 * @param string $entry
200 * @return \mdref\Entry
201 * @throws \OutOfBoundsException
203 public function getEntry(string $entry) : Entry
{
204 return new Entry($entry, $this);
208 * Get the root Entry instance
209 * @return \mdref\Entry
211 public function getRootEntry() : Entry
{
212 return new Entry($this->name
, $this);
216 * Implements \IteratorAggregate
217 * @return \mdref\Tree
219 public function getIterator() : Tree
{
220 return new Tree($this->path
, $this);