web(debug)

Launch web interface for CodeGarden.

Parameters:

Name Type Description Default
debug bool

Debug mode

required
Source code in code_garden/__main__.py
13
14
15
16
17
18
19
20
21
22
23
24
25
@cli.command()
@click.option("--debug", "-d", is_flag=True)
def web(debug: bool):
    """Launch web interface for CodeGarden.

    Args:
        debug (bool): Debug mode
    """
    app = create_app(config)
    if not debug:
        webbrowser.open(f"http://localhost:{config.PORT}/")
    app.config["ENV"] = "development" if debug else "production"
    app.run(port=config.PORT, debug=debug)

Branch

Bases: object

Branch object.

Attributes:

Name Type Description
repository str

name of the containing Repository

name str

name of this branch.

Source code in code_garden/models.py
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
class Branch(object):
    """Branch object.

    Attributes:
        repository (str): name of the containing Repository
        name (str): name of this branch.
    """

    def __init__(self, repository, name):
        self.repository = repository
        self.name = name

    def create(self):
        """Create a new branch."""
        Repository(self.repository).run_command(["git", "checkout", "-b", self.name])

    def delete(self):
        """Delete this branch."""
        Repository(self.repository).run_command(["git", "branch", "-D", self.name])

    def checkout(self):
        """Checkout this branch."""
        Repository(self.repository).run_command(["git", "checkout", self.name])

    def merge(self, other_branch):
        """Merge this branch with another.

        Args:
            other_branch (str): Other branch to merge with.
        """
        Repository(self.repository).run_command(["git", "merge", other_branch])

    def to_dict(self):
        """Get a dict representation of this object (for API use)."""
        return dict(
            repository=self.repository,
            name=self.name,
            comparison=[i.to_dict() for i in self.compare()],
        )

checkout()

Checkout this branch.

Source code in code_garden/models.py
212
213
214
def checkout(self):
    """Checkout this branch."""
    Repository(self.repository).run_command(["git", "checkout", self.name])

create()

Create a new branch.

Source code in code_garden/models.py
204
205
206
def create(self):
    """Create a new branch."""
    Repository(self.repository).run_command(["git", "checkout", "-b", self.name])

delete()

Delete this branch.

Source code in code_garden/models.py
208
209
210
def delete(self):
    """Delete this branch."""
    Repository(self.repository).run_command(["git", "branch", "-D", self.name])

merge(other_branch)

Merge this branch with another.

Parameters:

Name Type Description Default
other_branch str

Other branch to merge with.

required
Source code in code_garden/models.py
216
217
218
219
220
221
222
def merge(self, other_branch):
    """Merge this branch with another.

    Args:
        other_branch (str): Other branch to merge with.
    """
    Repository(self.repository).run_command(["git", "merge", other_branch])

to_dict()

Get a dict representation of this object (for API use).

Source code in code_garden/models.py
224
225
226
227
228
229
230
def to_dict(self):
    """Get a dict representation of this object (for API use)."""
    return dict(
        repository=self.repository,
        name=self.name,
        comparison=[i.to_dict() for i in self.compare()],
    )

DiffItem

Bases: object

Changed item in the Repository.

Attributes:

Name Type Description
repository str

name of the containing Repository

name str

name of this file.

Source code in code_garden/models.py
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
class DiffItem(object):
    """Changed item in the Repository.

    Attributes:
        repository (str): name of the containing Repository
        name (str): name of this file.
    """

    def __init__(self, repository, name):
        self.repository = repository
        self.name = name

    @property
    def path(self):
        return Repository(self.repository).path / self.name

    def reset(self):
        """Reset this file to its original state in the most recent commit."""
        Repository(self.repository).run_command(
            ["git", "checkout", "HEAD", "--", str(self.path)]
        )

    def to_dict(self):
        """Get a dict representation of this object (for API use)."""
        return dict(repository=self.repository, name=self.name, path=str(self.path))

reset()

Reset this file to its original state in the most recent commit.

Source code in code_garden/models.py
330
331
332
333
334
def reset(self):
    """Reset this file to its original state in the most recent commit."""
    Repository(self.repository).run_command(
        ["git", "checkout", "HEAD", "--", str(self.path)]
    )

to_dict()

Get a dict representation of this object (for API use).

Source code in code_garden/models.py
336
337
338
def to_dict(self):
    """Get a dict representation of this object (for API use)."""
    return dict(repository=self.repository, name=self.name, path=str(self.path))

IgnoreItem

Bases: object

Ignored items found in the .gitignore file.

Attributes:

Name Type Description
repository str

name of the containing Repository

name str

name of this file.

Source code in code_garden/models.py
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
class IgnoreItem(object):
    """Ignored items found in the .gitignore file.

    Attributes:
        repository (str): name of the containing Repository
        name (str): name of this file.
    """

    def __init__(self, repository, name):
        self.repository = repository
        self.name = name

    def create(self):
        """Add this item to the .gitignore."""
        ignores_ = Repository(self.repository).ignored
        ignores_.append(self)

        with open((Repository(self.repository).path / ".gitignore"), "w") as f:
            for i in ignores_:
                f.write(f"{i.name}\n")

    @classmethod
    def delete(cls, repository, id):
        """Delete an Ignore item.

        Args:
            repository (str): name of the Repository that contains this Ignore item.
            id (int): index, or location, of the Ignore item in the list.
        """
        ignores_ = Repository(repository).ignored
        del ignores_[id]

        with open((Repository(repository).path / ".gitignore"), "w") as f:
            for i in ignores_:
                f.write(f"{i.name}\n")

    def to_dict(self):
        """Get a dict representation of this object (for API use)."""
        return dict(repository=self.repository, name=self.name)

create()

Add this item to the .gitignore.

Source code in code_garden/models.py
353
354
355
356
357
358
359
360
def create(self):
    """Add this item to the .gitignore."""
    ignores_ = Repository(self.repository).ignored
    ignores_.append(self)

    with open((Repository(self.repository).path / ".gitignore"), "w") as f:
        for i in ignores_:
            f.write(f"{i.name}\n")

delete(repository, id) classmethod

Delete an Ignore item.

Parameters:

Name Type Description Default
repository str

name of the Repository that contains this Ignore item.

required
id int

index, or location, of the Ignore item in the list.

required
Source code in code_garden/models.py
362
363
364
365
366
367
368
369
370
371
372
373
374
375
@classmethod
def delete(cls, repository, id):
    """Delete an Ignore item.

    Args:
        repository (str): name of the Repository that contains this Ignore item.
        id (int): index, or location, of the Ignore item in the list.
    """
    ignores_ = Repository(repository).ignored
    del ignores_[id]

    with open((Repository(repository).path / ".gitignore"), "w") as f:
        for i in ignores_:
            f.write(f"{i.name}\n")

to_dict()

Get a dict representation of this object (for API use).

Source code in code_garden/models.py
377
378
379
def to_dict(self):
    """Get a dict representation of this object (for API use)."""
    return dict(repository=self.repository, name=self.name)

LogItem

Bases: object

Commit item from log.

Attributes:

Name Type Description
repository str

name of the containing Repository

name str

subject line of this commit.

Source code in code_garden/models.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
class LogItem(object):
    """Commit item from log.

    Attributes:
        repository (str): name of the containing Repository
        name (str): subject line of this commit.
    """

    def __init__(self, repository, name, timestamp, abbrev_hash):
        self.repository = repository
        self.name = name
        self.timestamp = timestamp
        self.abbrev_hash = abbrev_hash

    def to_dict(self):
        """Get a dict representation of this object (for API use)."""
        return dict(
            repository=self.repository,
            name=self.name,
            timestamp=self.timestamp.strftime("%B %-d, %Y @ %-I:%M %p"),
            abbrev_hash=self.abbrev_hash,
        )

to_dict()

Get a dict representation of this object (for API use).

Source code in code_garden/models.py
247
248
249
250
251
252
253
254
def to_dict(self):
    """Get a dict representation of this object (for API use)."""
    return dict(
        repository=self.repository,
        name=self.name,
        timestamp=self.timestamp.strftime("%B %-d, %Y @ %-I:%M %p"),
        abbrev_hash=self.abbrev_hash,
    )

Repository

Bases: object

A Git repository object.

All Repositories should have (1) a README.md file, and (2) a .git folder.

Attributes:

Name Type Description
path

Full path of the Repository.

branches

All local branches of the Repository.

current_branch

The currently checked-out branch.

log

List of (5 default) commits, sorted by most recent.

todos

List of tasks found in the todos.txt file.

diffs

List of all changed file in the current Repository.

readme

Dict object of text in the README.md file 'txt' is the plaintext content, 'md' is the Markdown-formatted text.

ignored

List of items in the .gitignore file.

Source code in code_garden/models.py
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
class Repository(object):
    """A Git repository object.

    All Repositories should have (1) a README.md file, and (2) a .git folder.

    Attributes:
        path: Full path of the Repository.
        branches: All local branches of the Repository.
        current_branch: The currently checked-out branch.
        log: List of (5 default) commits, sorted by most recent.
        todos: List of tasks found in the todos.txt file.
        diffs: List of all changed file in the current Repository.
        readme: Dict object of text in the README.md file 'txt' is the plaintext content, 'md' is the Markdown-formatted text.
        ignored: List of items in the .gitignore file.

    """

    def __init__(self, name: str):
        self.name = name

    @property
    def path(self):
        return config.HOME_DIR / self.name

    def run_command(self, cmd: list):
        """Run command in the Repository's directory.

        Args:
            cmd (list): List of arguments in the command. (splitting whitespace on text is recommended)
        """
        return subprocess.run(cmd, cwd=self.path, text=True, capture_output=True).stdout

    @property
    def branches(self):
        return [
            Branch(self.name, i.strip())
            for i in self.run_command(["git", "branch"]).split("\n")
            if i.strip()
        ]

    @property
    def current_branch(self):
        for i in self.run_command(["git", "branch"]).split("\n"):
            if i.startswith("* "):
                return i.replace("* ", "")

    @property
    def log(self):
        _ = []
        for i in self.run_command(
            ["git", "log", "--oneline", "-5", "--pretty=format:%s\t%at\t%h"]
        ).split("\n"):
            if len(i.strip().split("\t")) == 2:
                _.append(
                    LogItem(
                        self.name,
                        "[No Commit Message]",
                        datetime.datetime.min,
                        i.strip().split("\t")[0],
                    )
                )
            else:
                _.append(
                    LogItem(
                        self.name,
                        i.strip().split("\t")[0],
                        datetime.datetime.fromtimestamp(int(i.split("\t")[1])),
                        i.strip().split("\t")[2],
                    )
                )

        return _

    @property
    def todos(self):
        return (
            [
                Todo(self.name, i.strip())
                for i in open(self.path / "todos.txt").readlines()
                if i.strip()
            ]
            if (self.path / "todos.txt").exists()
            else []
        )

    @property
    def diffs(self):
        return [
            DiffItem(self.name, (self.path / i.strip().split()[1]).name)
            for i in self.run_command(["git", "status", "--short"]).split("\n")
            if i.strip()
        ]

    @property
    def readme(self):
        raw = open(self.path / "README.md").read()
        return dict(txt=raw, md=markdown.markdown(raw))

    @property
    def ignored(self):
        return [
            IgnoreItem(self.name, i.strip())
            for i in open(self.path / ".gitignore").readlines()
            if i.strip()
        ]

    @classmethod
    def all(cls):
        """Get all Repositories in the home directory."""
        return [
            Repository(i.name)
            for i in config.HOME_DIR.iterdir()
            if i.is_dir() and (i / ".git").exists()
        ]

    def init(self, brief_descrip: str):
        """Create a new Repository.

        Args:
            brief_descrip (str): Short description of what the Repository contains.
        """
        self.path.mkdir()
        open(self.path / "README.md", "w").write(
            f"# {self.name}\n---\n\n{brief_descrip}\n"
        )
        (self.path / "LICENSE.md").touch()
        open(self.path / ".gitignore", "w").write("todos.txt\n")
        (self.path / "todos.txt").touch()
        self.run_command(["git", "init"])
        self.commit("Initial commit", True)

    @classmethod
    def clone(cls, url: str):
        """Clone a Repository.

        Args:
            url (str): URL of the Git Repository.
        """
        subprocess.run(["git", "clone", url], cwd=config.HOME_DIR)

    def delete(self):
        """Delete this Repository."""
        shutil.rmtree(self.path)

    def edit_readme(self, content: str):
        """Edit this Repository's README file.

        Args:
            content (str): New plaintext content of the README.
        """
        open((self.path / "README.md"), "w").write(content)

    def commit(self, msg: str):
        """Commit all local changes to git.

        Args:
            msg (str): Commit message.
        """
        self.run_command(["git", "add", "-A"])
        self.run_command(["git", "commit", "-am", msg])

    def reset_all(self):
        """Discard all local changes, reset Repository to most recent commit."""
        self.run_command(["git", "checkout", "."])
        self.run_command(["git", "clean", "-fd"])

    def to_dict(self):
        """Get a dict representation of the Repository object (for API usage)."""
        return dict(
            name=self.name,
            path=str(self.path),
            branches=[i.to_dict() for i in self.branches],
            current_branch=self.current_branch,
            log=[i.to_dict() for i in self.log],
            todos=[i.to_dict() for i in self.todos],
            diffs=[i.to_dict() for i in self.diffs],
            readme=self.readme,
            ignored=[i.to_dict() for i in self.ignored],
        )

all() classmethod

Get all Repositories in the home directory.

Source code in code_garden/models.py
117
118
119
120
121
122
123
124
@classmethod
def all(cls):
    """Get all Repositories in the home directory."""
    return [
        Repository(i.name)
        for i in config.HOME_DIR.iterdir()
        if i.is_dir() and (i / ".git").exists()
    ]

clone(url) classmethod

Clone a Repository.

Parameters:

Name Type Description Default
url str

URL of the Git Repository.

required
Source code in code_garden/models.py
142
143
144
145
146
147
148
149
@classmethod
def clone(cls, url: str):
    """Clone a Repository.

    Args:
        url (str): URL of the Git Repository.
    """
    subprocess.run(["git", "clone", url], cwd=config.HOME_DIR)

commit(msg)

Commit all local changes to git.

Parameters:

Name Type Description Default
msg str

Commit message.

required
Source code in code_garden/models.py
163
164
165
166
167
168
169
170
def commit(self, msg: str):
    """Commit all local changes to git.

    Args:
        msg (str): Commit message.
    """
    self.run_command(["git", "add", "-A"])
    self.run_command(["git", "commit", "-am", msg])

delete()

Delete this Repository.

Source code in code_garden/models.py
151
152
153
def delete(self):
    """Delete this Repository."""
    shutil.rmtree(self.path)

edit_readme(content)

Edit this Repository's README file.

Parameters:

Name Type Description Default
content str

New plaintext content of the README.

required
Source code in code_garden/models.py
155
156
157
158
159
160
161
def edit_readme(self, content: str):
    """Edit this Repository's README file.

    Args:
        content (str): New plaintext content of the README.
    """
    open((self.path / "README.md"), "w").write(content)

init(brief_descrip)

Create a new Repository.

Parameters:

Name Type Description Default
brief_descrip str

Short description of what the Repository contains.

required
Source code in code_garden/models.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def init(self, brief_descrip: str):
    """Create a new Repository.

    Args:
        brief_descrip (str): Short description of what the Repository contains.
    """
    self.path.mkdir()
    open(self.path / "README.md", "w").write(
        f"# {self.name}\n---\n\n{brief_descrip}\n"
    )
    (self.path / "LICENSE.md").touch()
    open(self.path / ".gitignore", "w").write("todos.txt\n")
    (self.path / "todos.txt").touch()
    self.run_command(["git", "init"])
    self.commit("Initial commit", True)

reset_all()

Discard all local changes, reset Repository to most recent commit.

Source code in code_garden/models.py
172
173
174
175
def reset_all(self):
    """Discard all local changes, reset Repository to most recent commit."""
    self.run_command(["git", "checkout", "."])
    self.run_command(["git", "clean", "-fd"])

run_command(cmd)

Run command in the Repository's directory.

Parameters:

Name Type Description Default
cmd list

List of arguments in the command. (splitting whitespace on text is recommended)

required
Source code in code_garden/models.py
35
36
37
38
39
40
41
def run_command(self, cmd: list):
    """Run command in the Repository's directory.

    Args:
        cmd (list): List of arguments in the command. (splitting whitespace on text is recommended)
    """
    return subprocess.run(cmd, cwd=self.path, text=True, capture_output=True).stdout

to_dict()

Get a dict representation of the Repository object (for API usage).

Source code in code_garden/models.py
177
178
179
180
181
182
183
184
185
186
187
188
189
def to_dict(self):
    """Get a dict representation of the Repository object (for API usage)."""
    return dict(
        name=self.name,
        path=str(self.path),
        branches=[i.to_dict() for i in self.branches],
        current_branch=self.current_branch,
        log=[i.to_dict() for i in self.log],
        todos=[i.to_dict() for i in self.todos],
        diffs=[i.to_dict() for i in self.diffs],
        readme=self.readme,
        ignored=[i.to_dict() for i in self.ignored],
    )

Todo

Bases: object

Todo item found in todos.txt.

Attributes:

Name Type Description
repository str

name of the containing Repository

name str

description of this Todo item.

Source code in code_garden/models.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
class Todo(object):
    """Todo item found in todos.txt.

    Attributes:
        repository (str): name of the containing Repository
        name (str): description of this Todo item.
    """

    def __init__(self, repository, name):
        self.repository = repository
        self.name = name

    def create(self):
        """Create a new Todo."""
        todos_ = Repository(self.repository).todos
        todos_.append(self)

        with open((Repository(self.repository).path / "todos.txt"), "w") as f:
            for i in todos_:
                f.write(f"{i.name}\n")

    @classmethod
    def edit(cls, repository, id, new_name):
        """Edit a Todo item.

        Args:
            repository (str): name of the Repository that contains this Todo.
            id (int): index, or location, of the Todo in the list.
            new_name (str): new description of the Todo item.
        """
        todos_ = Repository(repository).todos
        todos_[id].name = new_name

        with open((Repository(repository).path / "todos.txt"), "w") as f:
            for i in todos_:
                f.write(f"{i.name}\n")

    @classmethod
    def delete(cls, repository, id):
        """Delete a Todo item.

        Args:
            repository (str): name of the Repository that contains this Todo.
            id (int): index, or location, of the Todo in the list.
        """
        todos_ = Repository(repository).todos
        del todos_[id]

        with open((Repository(repository).path / "todos.txt"), "w") as f:
            for i in todos_:
                f.write(f"{i.name}\n")

    def to_dict(self):
        """Get a dict representation of this object (for API use)."""
        return dict(repository=self.repository, name=self.name)

create()

Create a new Todo.

Source code in code_garden/models.py
269
270
271
272
273
274
275
276
def create(self):
    """Create a new Todo."""
    todos_ = Repository(self.repository).todos
    todos_.append(self)

    with open((Repository(self.repository).path / "todos.txt"), "w") as f:
        for i in todos_:
            f.write(f"{i.name}\n")

delete(repository, id) classmethod

Delete a Todo item.

Parameters:

Name Type Description Default
repository str

name of the Repository that contains this Todo.

required
id int

index, or location, of the Todo in the list.

required
Source code in code_garden/models.py
294
295
296
297
298
299
300
301
302
303
304
305
306
307
@classmethod
def delete(cls, repository, id):
    """Delete a Todo item.

    Args:
        repository (str): name of the Repository that contains this Todo.
        id (int): index, or location, of the Todo in the list.
    """
    todos_ = Repository(repository).todos
    del todos_[id]

    with open((Repository(repository).path / "todos.txt"), "w") as f:
        for i in todos_:
            f.write(f"{i.name}\n")

edit(repository, id, new_name) classmethod

Edit a Todo item.

Parameters:

Name Type Description Default
repository str

name of the Repository that contains this Todo.

required
id int

index, or location, of the Todo in the list.

required
new_name str

new description of the Todo item.

required
Source code in code_garden/models.py
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
@classmethod
def edit(cls, repository, id, new_name):
    """Edit a Todo item.

    Args:
        repository (str): name of the Repository that contains this Todo.
        id (int): index, or location, of the Todo in the list.
        new_name (str): new description of the Todo item.
    """
    todos_ = Repository(repository).todos
    todos_[id].name = new_name

    with open((Repository(repository).path / "todos.txt"), "w") as f:
        for i in todos_:
            f.write(f"{i.name}\n")

to_dict()

Get a dict representation of this object (for API use).

Source code in code_garden/models.py
309
310
311
def to_dict(self):
    """Get a dict representation of this object (for API use)."""
    return dict(repository=self.repository, name=self.name)