Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution to assignment-4 (assignment-2.1 on hold) #58

Open
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

Hemant-Chowdhury
Copy link

Please review the pull request.
Commands used in the assignment are compatible with the windows operating system.
The code is taking 3-5s to execute test.py

Copy link
Owner

@kaustubh-karkare kaustubh-karkare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good start!
Now that I've seen how you've solved part1, you should start working on part2 of the problem too.

solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/test1/test.cpp Outdated Show resolved Hide resolved
solutions/assignment-2/test.py Outdated Show resolved Hide resolved
solutions/assignment-2/test1/build_auto.py Outdated Show resolved Hide resolved
solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/test.py Outdated Show resolved Hide resolved
@Hemant-Chowdhury
Copy link
Author

please review the pull request

Copy link
Owner

@kaustubh-karkare kaustubh-karkare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent progress!

solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/build.py Outdated Show resolved Hide resolved
solutions/assignment-2/graph.py Outdated Show resolved Hide resolved

cmd = r'python build.py --root=~\tmp\ parent'
output = subprocess.check_output(cmd, shell=True)
self.assertEqual(output, b'Error: Undefined dependencies found "B".\r\n')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message can explain which build rule tried to depend on it.

C
/ \
D E
"""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@@ -0,0 +1,632 @@
import os
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, this file is too large. You can split it down into smaller ones.

std::cout<<"sort_merge_modified";
}
""")
sleep(10)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests with sleep statements are non-ideal, since they make you wait.
Can you modify your code so that something like this is possible?

# assuming something like:
def watch():
  with True:
    self.check_and_maybe_execute()

And then you call check_and_maybe_execute from this file, eliminating any wait.

self.delete_file_structure(root='tmp')

def test_ignore_files(self):
FILE_STRUCTURE = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this has been repeated a few times, make it a class level variable and share it? You can use it like a template, and add modifications on top of a deepcopy.

[
{
"name": "runA",
"deps": ["dirB\\runB"],
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Earlier you mentioned that "dirB\\runB" is quite confusing and it does not tell whether it is an absolute path or relative path.
Here, I have assumed that all the entries which come in the "deps" is a relative path, and \\ is used to handle the escape character \, since I am using Windows os, separators for os.path is \
Any changes to "dirB\\runB" like ".\dirB\\runB" or "\\dirB\runB" was difficult because entries in "deps" should match with some "name".

Copy link
Owner

@kaustubh-karkare kaustubh-karkare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good!

  • There are lots of different things going on in you build.py file. You should break it down into pieces: one file for the classes for rules, another file for executing them, another to watch for changes.
  • Don't separate your file structure from your tests, since they're conceptually linked. As a reader, it is ideal if all the information relevant to a single test is in one location. Feel free to separate the tests across multiple files to keep them easily readable and use a test_utils.py module to share code where needed.
  • I updated the problem statement to add another requirement: parallel execution of rules without multithreading. Lets do that too :)

Comment on lines 28 to 29
if os.path.getmtime(self.filename) != self.last_modified:
self.last_modified = os.path.getmtime(self.filename)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call os.path.getmtime only once, since it is unnecessary duplication computation.

Comment on lines 42 to 43
if 'deps' in properties:
self.dependent_rulenames = properties['deps']
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.dependent_rulenames = properties.get('deps', [])

parser.add_argument('--watch', action='store_true', help='Status to build again on file modification')
parser.add_argument('--poll', type=float, default=1, help='Time interval for checking the file modification status')
parser.add_argument('--ignore', nargs='*', type=str, help='List of files not to be watched')
return vars(parser.parse_args(arguments))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the benefit of using vars here?

self.build_rules: Dict[str, Rule] = dict()
self.build_files: Dict[str, File] = dict()
self.build_arguments: Dict[str, Any] = self._parse(arguments)
self.build_arguments['root'] = os.path.realpath(self.build_arguments['root'])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing this in a separate phase, you can try:

parser.add_argument('--root', type=lambda path: os.path.realpath(path), ...

class File(object):
"""docstring for File"""

def __init__(self, filename: str, is_BUILD_FILE: bool=False):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confusing use of capital letters here ... why not just use "is_build_file"?

processed: Dict[Any, int] = {key: -1 for key in self.adjacency_list}
dfs_list: List[Any] = list()
self._dfs(source, processed, dfs_list)
dfs_list.reverse()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You reversed this list here, and also in the other file where you called this method. Unnecessary work?

supporter_list: Dict[str, List[str]] = {key: list() for key in self.build_rules}
for file_name in self.build_files:
if not self.build_files[file_name].is_BUILD_FILE:
supporter_list[file_name] = list()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, so the keys of supporter_list include both rule names and file names? Mixing things like that is probably not a good idea, and it looks like this only matters in the first step of your traversal (filename -> rule name), so you can do that manually.

raise BuildAutomationError(f'Invalid rule "{rulename}" provided')
dependent_rulenames = self.get_dependent_rulenames_for_executing_rule(rulename)
for dependent_rulename in dependent_rulenames:
output += self.build_rules[dependent_rulename].execute()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See Part2 of updated problem statement.

def check_and_maybe_execute(self) -> str:
output = ''
for filename in self.build_files:
if filename not in self.ignored_files:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return/continue/break early to reduce indenting.

if filename in self.ignored_files:
  continue

def execute(self) -> str:
process = subprocess.Popen(self.command.split(), stdout=subprocess.PIPE, shell=True)
(out, err) = process.communicate()
return out.decode()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don't think that the stdout of the process is a reliable indicator of success. I'd recommend using return value.

@Hemant-Chowdhury Hemant-Chowdhury changed the title Solution to assignment-2.1 Solution to assignment-4 (assignment-2.1 on hold) Nov 23, 2019
# pass


class commit(object):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with open(os.path.join(vcs_files.OBJECTS, self.get_hash()), 'w') as commit_file:
commit_file.write(self.get_content())

def set_hash(self, hash: str) -> None:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method does everything except what the name says.

os.remove(filename)

def setUp(self):
test_dir = 'test_dir'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.chdir(test_dir)

def test_init(self):
result = Init.init()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use your vcs class here?

self.status = 'Initializing vcs in this directory'
self.check_and_create_files()

def check_and_create_files(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code works in case an incomplete set of those folders/files already exists.
I'm not sure if that's a good idea. Ie - if you find something partial, I would imagine it is safer to raise an exception, and ask the user to delete the things.

return
commit_object = Object.commit()
commit_object.set_parent(Object.get_HEAD())
tree_object = self._save_object(os.getcwd())
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the repo contains multiple nested folders?
Will the commit only capture the current one?

with open(old_file, 'r') as read_old_file:
self.old_file_lines = read_old_file.read().split('\n')

def _lcs(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must have been fun to implement :)

import unittest


class TestVCS(unittest.TestCase):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is doing too many things IMO.
For the sake of readability, I would recommend multiple smaller test files, so that you can test your utility methods like LCS specifically too, not just the commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants