| Question | Mark |
| 1. Git, merge conflicts [8 marks] | |
| 2. Bash, regular expressions [8 marks] | |
| 3. Bash scripting [8 marks] | |
| 4. Specifications [8 marks] | |
| 5. Life cycle models [8 marks] | |
| 6. Makefiles [8 marks] | |
| Exam Total [40 marks] |
Question 1: Git, merge conflicts coding [8]
The table below show the branch history and (using cat) the contents of files in a repository, ending with a merge attempt that results in a merge conflict. (The linux prompt is shown as > in the table.)
> mkdir Q1 > cd Q1 > git init-db > vi readme > cat readme Here is the project readme, not very interesting, but it's a dull project. > git add . > git commit -m "preliminary project repo" [master (root-commit) b5025b0] preliminary project repo 2 files changed, 2 insertions(+) create mode 100644 readme create mode 100644 typescript > git branch expt > git checkout expt Switched to branch 'expt' > vi datafile > cat datafile Here is the data to be used in the expt branch. > git add . > git commit -m "added data file for testing" [expt 7193202] added data file for testing 1 file changed, 2 insertions(+) create mode 100644 datafile > git checkout master Switched to branch 'master' > vi datafile > cat datafile Test data to be used in the master branch > git add . > git commit -m "set up test data in datafile" [master 2a3ba8f] set up test data in datafile 1 file changed, 1 insertion(+) create mode 100644 datafile > git checkout expt Switched to branch 'expt' > git merge master Auto-merging datafile CONFLICT (add/add): Merge conflict in datafile Automatic merge failed; fix conflicts and then commit the result. |
First, if you were now to open the conflicted file, show what the contents of the file would look like.
Second, explain how you would resolve/complete the merge if you wanted the file to keep all the contents from both versions.
Sample Solution: <<<<<<< HEAD Here is the data to be used in the expt branch. ======= Test data to be used in the master branch >>>>>>> master To complete the merge, keeping both files' content, simply remove the lines <<<, ===, and >>> then save. The merge will complete, and you can add, and commit as necessary. |
Question 2: Bash, regular expressions [8]
Below we show a bash script followed by three separate attempts to run it.
For each of the attempts to run the script, show as precisely as possible, the output the script would produce and briefly explain the results.
#! /bin/bash
# HINT: \b matches a word boundary (like $ and ^ match line boundaries)
pat1='\b[0-9]?[a-z]+'
pat2='[0-9]*[aeiou]+\b'
pat3='123*[a-z]?'
i=1
for arg in $@ ; do
echo "argument $i is $arg"
i=$[$i+1]
if [[ $arg =~ $pat1 ]] ; then
echo " ... matches pattern 1"
elif [[ $arg =~ $pat2 ]] ; then
echo " ... matches pattern 2"
elif [[ $arg =~ $pat3 ]] ; then
echo " ... matches pattern 3"
else
echo " ... matches no patterns"
fi
done
|
Sample Solution:
> q2.sh
> q2.sh '"12"' 12a
argument 1 is "12"
... matches pattern 3
argument 2 is 12a
... matches pattern 2
> q2.sh foo 123123a
argument 1 is foo
... matches pattern 1
argument 2 is 123123a
... matches pattern 2
Explanation:
Pattern 1 matches any word that starts with 0 or 1 digits
followed by any number of lowercase alphabetic characters,
so it effectively matches anything that begins with a digit
or begins with an a-z.
Pattern 2 matches any word that ends with 0 or more digits
followed by one or more lowercase vowels (aeiou), so it
effectively matches anything ending with a vowel.
Pattern 3 matches any word that contains "12" followed by any
number of 3's and then 0 or 1 lowercase alphabetic characters,
so it effectively matches anything containing 12.
q2.sh
has no command line arguments, so never enters the for loop,
so produces absolutely no output at all.
q2.sh '"12"' 12a
has two command line arguments, the first is the string "12" (with the quotes)
and the second is the string 12a
the first does not match pattern 1 or 2, but does match pattern 3
the second does not match pattern 1 but does match pattern 2
(it would also have matched pattern 3, but we never get there)
q2.sh foo 123123a
has two command line arguments, the first is the string foo,
and the second is the string 123123a
the first matches pattern 1
the second matches pattern 2
(again, it would also have matched pattern 3, but we never get there)
|
Question 3: Bash scripting [8]
Write a complete and correct bash script that meets the following specifications:
The script is intended as an organizational aid for students using the csci git repository system.
(i) If run with no arguments, it shows the user a list of all the repositories they have access to on the central csci server, followed by a list of every repository they have in the trash on the central server.
(ii) If run with one or more arguments, it treats those arguments as keywords, and only
shows those repositories which contain all the keywords. For example, the command
./showRepos.sh csci265 lab4
would show the user's central repositories and trash that contain both csci265 and lab4, e.g.
something like:
Central server trash contents: csci265/wesselsd/lab04a/2017-10-02_07:41:28 Central server repositories accessible: R csci265/wesselsd/lab04a R W csci265/lab04a R W csci265/lab04bHINTS/REMINDERS:
Sample Solution: #! /bin/bash # get the total output from both ssh commands and store in variables repoInfo=`ssh csci info` trashInfo=`ssh csci D list-trash` # for each command line argument that was supplied, # keep only those lines that contain the pattern # note: the double quotes are necessary around the $tmp and $pattern # to maintain whitespace, particularly the newlines, # otherwise the echo dumps all the base output into one big line, # so grep can't actually filter line-by-line for pattern in $@; do tmp=$repoInfo repoInfo=`echo "$tmp" | grep "$pattern"` tmp=$trashInfo trashInfo=`echo "$tmp" | grep "$pattern"` done # display the filtered result echo "Central repository contents requested:" echo $repoInfo echo "Central repository trash listings requested:" echo $trashInfo |
Question 4: Specifications [8]
Critique the specifications for the nameSorter function below, under the assumption that, as this is just a part of a larger program, the code standards and processes, operating environment, and choice of language are already documented elsewhere.
For any problems/weaknesses you have identified, suggest an alternative wording for the specifications that illustrates how the problem/weakness could be fixed.
// function nameSorter // ------------------- // given an array of names and the array size as parameters, // sort the array alphabetically. // return true if successful, false otherwise bool nameSorter(string names[], int nameSize) |
Sample Solution:
Key issues:
(1) It should be explicitly stated that the function actually modifies the
contents of the names array, storing the sorted content there.
(2) nameSize is somewhat misleading as a name, since it actually contains
the size of the array, not the size of a name.
(3) It is unclear what "sorted alphabetically" actually means, and that
will be difficult to clarify without identifying what a valid name
looks like. For example, is the format "J. Doe", "Doe, J." or is
it something else, and is sorting alphabetically increasing or decreasing?
(4) It is unclear what constitutes an "unsuccessful" sort, and hence when
a value of false should be returned. For example, should the function
return false if nameSize < 0? if nameSize == 0? if a null value is
passed for names? if the array contains duplicates? if there are
duplicate names? if names contain invalid characters or have an
invalid format? (and if so, just what *are* the invalid characters
and invalid formats?)
Possible rewording:
Given an array of names as strings (in parameter names), and the size of
the array as an integer (in parameter arraySize), sort the array in
alphabetically non-decreasing order based on the full content of the
string provided (e.g. "Fred Jones" comes before "Scoobert Doo").
The sorted results replace the current contents of the names array.
Names must consist of one or more printable characters, but must contain
at least one non-whitespace character. Duplicate names are possible.
The function returns false under any of the following conditions:
- if a null value is passed as the array,
- if an arraySize less than 1 is passed,
- if any name does not satisfy the criteria above.
Under any other circumstances the function returns true when complete.
The profile for the function is as follows:
bool nameSorter(string names[], int arraySize);
|
Question 5: Life cycle models [8]
Given the hypothetical project description below, provide a preliminary recommendation on a software development life cycle model for the project. Justify your recommendation, and discuss its strengths and weaknesses with respect to this specific project.
Project RepoManager
Sample Solution:
Whatever model you picked, your discussion needs to convince me that you have
considered the advantages and disadvantages of your chosen model over the other
available choices, and justifies why you think the advantages outweight the
disadvantages for this specific project.
Some of the key points to address included:
Concerns going into the project
- the relatively short time frame (four months, for students who are each
only available 10 hours per week)
- the limited amount of supervision/guidance available
- the lack of clear/detailed requirements at the outset of the project
- the lack of advanced development experience of the team members
- the lack of planned/formal interaction with the end user base (other CS students)
- the possible communication/coordination issues arising from having a team
of five people with limited contact hours per week
Strengths going into the project
- the team members all have direct experience with the tasks the tool is
meant to automate, and would presumably be end users when it is complete
(although they do not yet have personal experience with what may be
expected from the tool by upper level students)
- the team members are peers, with comperable skills and experience
|
Question 6: Makefiles [8]
The tables below show the contents of a makefile and the modification times/dates of the relevant files within its directory.
(i) Assuming the user were now to type the command "make all", show the output that would be produced by the makefile. (You may assume that everything that is recompiled does compile cleanly.)
(ii) If the user then typed the commands "make clean" followed by "make", show the output that would be produced by the makefile. (Again assuming there are no compilation errors or warnings.)
# makefile
Compiler=g++
BaseFlags=-Wall -Wextra -DNDebug
DebugFlags=-g
ObjFlags=-c
Dbg=Off
CC=
Obj=obj/stack.o obj/list.o obj/app.o obj/tester.o
Hdrs=hdr/stack.h hdr/defs.h hdr/list.h hdr/tester.h
Src=src/stack.cpp src/list.cpp src/app.cpp src/tester.cpp
Exe=bin/app bin/tester
ifeq (${Dbg},Off)
CC=${Compiler} ${BaseFlags}
else
CC=${Compiler} ${BaseFlags} ${DebugFlags}
endif
all: ${Exe}
bin/app: obj/stack.o obj/list.o obj/app.o
${CC} obj/stack.o obj/list.o obj/app.o -o bin/app
bin/tester: obj/stack.o obj/list.o obj/tester.o
${CC} obj/stack.o obj/list.o obj/tester.o -o bin/tester
obj/stack.o: src/stack.cpp hdr/stack.h hdr/defs.h
${CC} ${ObjFlags} src/stack.cpp -o obj/stack.o
obj/list.o: src/list.cpp hdr/list.h hdr/defs.h
${CC} ${ObjFlags} src/list.cpp -o obj/list.o
obj/app.o: src/app.cpp hdr/list.h hdr/defs.h hdr/stack.h
${CC} ${ObjFlags} src/app.cpp -o obj/app.o
obj/tester.o: src/tester.cpp hdr/list.h hdr/defs.h hdr/stack.h hdr/tester.h
${CC} ${ObjFlags} src/tester.cpp -o obj/tester.o
clean:
rm -f ${Obj}
|
Sample Solution:
g++ -Wall -Wextra -DNDebug -c src/stack.cpp -o obj/stack.o
g++ -Wall -Wextra -DNDebug -c src/app.cpp -o obj/app.o
g++ -Wall -Wextra -DNDebug obj/stack.o obj/list.o obj/app.o -o bin/app
g++ -Wall -Wextra -DNDebug -c src/tester.cpp -o obj/tester.o
g++ -Wall -Wextra -DNDebug obj/stack.o obj/list.o obj/tester.o -o bin/tester
rm -f obj/stack.o obj/list.o obj/app.o obj/tester.o
g++ -Wall -Wextra -DNDebug -c src/stack.cpp -o obj/stack.o
g++ -Wall -Wextra -DNDebug -c src/list.cpp -o obj/list.o
g++ -Wall -Wextra -DNDebug -c src/app.cpp -o obj/app.o
g++ -Wall -Wextra -DNDebug obj/stack.o obj/list.o obj/app.o -o bin/app
g++ -Wall -Wextra -DNDebug -c src/tester.cpp -o obj/tester.o
g++ -Wall -Wextra -DNDebug obj/stack.o obj/list.o obj/tester.o -o bin/tester
Explanation:
if we look at the file modification dates, we see that stack.h and tester.cpp
have been modified since the last time we built the .o's and executables
the only thing that does not actually depend on those two files is list.o,
everything else winds up being rebuilt in the order dictated by the
dependency checks in the makefile, completing the recursively called
.o targets before the executables that depend on them
|