gitstats: Extended setupRepo to create the repo as specified in metrics.txt
[git-stats.git] / src / scripts / setupRepo.py
blob9508638eebf3497c664ecf52c52a297675d9f750
1 #!/usr/bin/env python
3 import os
4 import tempfile
6 from git import Repo
7 from git import Git
9 testPath = os.path.join(tempfile.gettempdir(), "testrepo")
10 metricsPath = os.path.join(tempfile.gettempdir(), "metricsrepo")
12 class InitializationException(Exception):
13 """This exception is raised when something goes wrong during initialization.
14 """
16 def setupRepo(path):
17 """Creates a fresh repo under the specified path
19 If the specified path exists an exception is raised.
21 Args:
22 path: The path where the new repo should be created at.
23 """
25 print("Creating a new repository in " + path)
27 # Check if the path exists already, if so bail out
28 if os.path.exists(path):
29 raise InitializationException(
30 "The specified path, " + path + ", exists already, "
31 "please remove it or change the target path.")
33 # Create a new repo
34 repo = Repo.create(path)
35 os.chdir(path)
37 def setDefaultInfo():
38 """Configures GIT_COMMITTER_DATE etc to a default value.
40 These values are taken from t/test-lib.sh and t/t1400-update-ref.sh from
41 git.git. The actual date used is 2005-05-26 23:30
42 """
44 # Date taken from t/t1400-update-ref.sh
45 os.environ["GIT_COMMITTER_NAME"] = "C O Mitter"
46 os.environ["GIT_COMMITTER_EMAIL"] = "committer@example.com"
47 os.environ["GIT_COMMITTER_DATE"] = "2005-05-26 23:30"
48 os.environ["GIT_AUTHOR_NAME"] = "A U Thor"
49 os.environ["GIT_AUTHOR_EMAIL"] = "author@example.com"
50 os.environ["GIT_AUTHOR_DATE"] = "2005-05-26 23:30"
51 os.environ["TZ"] = "UTC"
53 def setSecondaryInfo():
54 """Configures GIT_COMMITTER_DATE and GIT_AUTHOR_DATE to a secondary value.
56 These values are taken from t/test-lib.sh and t/t1400-update-ref.sh from
57 git.git. The actual date used is 2005-05-26 23:30
58 """
61 os.environ["GIT_COMMITTER_NAME"] = "Retti Mmoc"
62 os.environ["GIT_COMMITTER_EMAIL"] = "retti.mmoc@example.com"
63 os.environ["GIT_COMMITTER_DATE"] = "2005-05-26 23:30"
64 os.environ["GIT_AUTHOR_NAME"] = "Roh Tua"
65 os.environ["GIT_AUTHOR_EMAIL"] = "roh.tua@example.com"
66 os.environ["GIT_AUTHOR_DATE"] = "2005-05-26 23:30"
67 os.environ["TZ"] = "UTC"
69 def addFile(filename, createFile=True, commit=True):
70 """Adds the specified file
72 Args:
73 filename: The name of the file to add.
74 createFile: Whether the file should be created.
75 """
77 if createFile:
78 file = open(filename, "w")
79 file.close()
81 git = Git(".")
83 git.add(filename)
85 if commit:
86 git.commit("-m", "Added file " + filename)
88 def deleteFile(filename, leaveOnDisk=False):
89 """Deletes the specified file
91 Args:
92 filename: The name of the file to delete.
93 leaveOnDisk: Whether the file should not be physically deleted.
94 """
96 args = []
98 # If the file should not be deleted, tell 'git rm' so
99 if leaveOnDisk:
100 args.append("--cached")
102 args.append(filename)
104 git = Git(".")
106 git.rm(*args)
108 git.commit("-m", "Deleted file " + filename)
110 def createLinearHistory(filename, createFile=False, initialCommit=False, start=1, count=10, finalCommit=False):
111 """Creates a linear history in the directory of the current repository.
113 The history is fairly simple and is all acted upon the specified file.
114 Any exceptions thrown during IO operations are _not_ cought.
116 Params:
117 filename: The name of the file in which to generate the history.
118 createFile: Whether the specified file has to be created first.
119 initialCommit: Whether to create an initial commit.
120 start: Which commit to start the history at.
121 count: The size of the history.
122 finalCommit: Whether to create a final commit.
125 git = Git(".")
127 stop = start + count
129 if createFile:
130 addFile(filename, commit=False)
132 # Create or open the content file
133 file = open(filename, "a")
135 if initialCommit:
136 # Start out with an initial change
137 file.write("Initial change\n")
138 file.flush()
140 # Add the file and create the initial commit
141 git.commit("-a", "-m", "Initial commit")
143 # Create a linear history
144 for i in range(start, stop):
145 file.write("Change " + str(i) + "\n")
146 file.flush()
148 git.commit("-a", "-m", "Commit " + str(i))
150 if finalCommit:
151 # Finish it up with a final change
152 file.write("Last change\n")
153 file.flush()
155 # And a final commit
156 git.commit("-a", "-m", "Last commit")
158 def createBranch(name, checkout=True):
159 """Creates a branch with the specified name and optionally checks it out
161 Params:
162 name: The name of the new branch.
163 checkout: Whether to perform a checkout of the branch.
166 git = Git(".")
168 git.branch(name)
170 if checkout:
171 checkoutBranch(name)
173 def createDir(name, changeDir=False):
174 """Creates a directory with the specified name
176 Args:
177 name: The name of the directory
180 os.mkdir(name)
182 def checkoutBranch(name):
183 """Switches to the specified branch
185 Params:
186 name: The name of the branch to be switched to.
189 git = Git(".")
191 git.checkout(name)
193 def checkoutRelease(release):
194 """Switches to the specified release
196 Params:
197 release: The release to check out
200 checkoutBranch('v' + str(release))
202 def mergeBranch(name):
203 """Merges the current branch with the specified branch
205 Params:
206 name: The name of the branch to merge with.
209 git = Git(".")
211 git.merge(name)
213 def revertLastCommit(commitChanges=True):
214 """Reverts the last commit made
216 Params:
217 commitChanges: Whether to commit the revert.
220 git = Git(".")
222 options = ["--no-edit", "HEAD"]
224 if not commitChanges:
225 options.append("-n")
227 git.revert(*options)
229 def tagRelease(releaseNumber):
230 """Tags a release.
232 The created tag is 'v' + releaseNumber.
234 Params:
235 releaseNumber: The number of the release.
238 git = Git(".")
240 git.tag('v' + str(releaseNumber))
242 def createRemoteBranch(name, start="HEAD"):
243 """Creates a new remote branch with the specified name
245 Args:
246 name: The plain name of the remote (no '/refs/remotes/' prefix)
247 start: The revision to branch off from
250 git = Git(".")
252 git.update_ref('refs/remotes/' + name, start)
254 def checkHead(HEAD):
255 """Verifies that the HEAD is as expected.
257 Params:
258 HEAD: The expected value of HEAD.
261 git = Git(".")
263 result = git.rev_parse("HEAD")
265 # Eat the trailing newline
266 currentHEAD = result[:-1]
268 scriptSuccessful = (HEAD == currentHEAD)
270 if scriptSuccessful:
271 print("Done, repo created successfully")
272 return True
273 else:
274 print("Something went wrong, current HEAD doesn't match.")
275 print("Expected: '" + HEAD + "'.")
276 print("Actual: '" + currentHEAD + "'.")
277 return False
279 def createTestRepository():
280 """Creates a test repository under setupRepo.testpath
283 # Directories
284 d = "docs"
286 # Files
287 c = "content.txt"
288 n = "notes.txt"
289 t = "test.c"
290 r = os.path.join(d, "README.txt")
292 # Branches
293 m = "master"
294 mt = "maint"
295 p = "pu"
296 e = "erase"
297 j = "junio"
299 # Start afresh
300 setupRepo(testPath)
302 # Set the default author/committer
303 setDefaultInfo()
305 # Create some linear history
306 createLinearHistory(c, createFile=True, initialCommit=True, finalCommit=True)
308 # Create a maintenance branch
309 createBranch(mt)
311 # Create some history there too
312 createLinearHistory(n, createFile=True, count=3)
314 # Go back to master and merge with maint
315 checkoutBranch(m)
316 mergeBranch(mt)
318 # Create a playground branch and create some history
319 # This branch will be left 'dead', e.g., unused after this
320 createBranch(p)
321 createLinearHistory(t, createFile=True, count=7, finalCommit=True)
323 # Revert that commit
324 revertLastCommit()
326 # Go back to master and continue some history
327 checkoutBranch(m)
328 createLinearHistory(c, start=10, count=5)
330 # Yay, our first release!
331 tagRelease(1)
333 # Merge current master into maint
334 checkoutBranch(mt)
335 mergeBranch(m)
337 # Ouch! Brown paper bag fix there, correct it and merge into master
338 revertLastCommit(commitChanges=False)
339 createLinearHistory(c, start=42, count=1)
340 checkoutBranch(m)
341 mergeBranch(mt)
343 # Continue some work on master
344 createLinearHistory(c, start=16, count=6)
346 # Have someone else do some work on master
347 setSecondaryInfo()
348 createLinearHistory(c, start=22, count=2)
350 # Go back to the initial data
351 setDefaultInfo()
353 # Create a directory for the documentation
354 createDir(d)
356 # Create a readme and add some content to it
357 createLinearHistory(r, createFile=True, count=5, finalCommit=True)
359 # Ah, but that last one was bad, we don't want it
360 revertLastCommit()
362 # Instead, continue the linear history
363 createLinearHistory(r, start=6, count=1)
365 # Come to think of it, that -was- a really good change after all
366 revertLastCommit()
368 # Reinstate that final commit
369 createLinearHistory(r, count=0, finalCommit=True)
371 # Create a branch to delete a file on
372 createBranch(e)
374 # Remove a file from git
375 deleteFile(r, leaveOnDisk=True)
377 # Only to add it back later so that we don't have any dangling files
378 addFile(r, createFile=False)
380 # Create a release at this point for easy switching later
381 tagRelease(2)
383 # Switch back to master for the test suite
384 checkoutBranch(m)
386 # Create a remote branch
387 createRemoteBranch(j, start="HEAD^")
389 return 0
391 def createMetricsRepository():
392 """Creates a metrics repository in setupRepo.metricspath
395 # files
396 c = "content.txt"
397 n = "notes.txt"
398 r = "README"
400 # branches
401 m = "master"
402 mt = "maint"
403 h = "help"
405 # Create a repository to work in
406 setupRepo(metricsPath)
408 # Set the info
409 setDefaultInfo()
411 # And create some history
412 createLinearHistory(c, createFile=True, count=2)
414 # Mark this commit so that we can jump back to it later
415 tagRelease(1)
417 # And create some more history
418 createLinearHistory(c, start=3, count=3)
420 # Go back to that marked commit
421 checkoutRelease(1)
423 # Now create a new branch to work on
424 createBranch(mt)
426 # Fix us up some more history
427 createLinearHistory(n, createFile=True, count=2)
429 # Mark this commit too so we can jump back
430 tagRelease(2)
432 # And make some more history
433 createLinearHistory(n, start=2, count=1)
435 # Now merge this back into master
436 checkoutBranch(m)
437 mergeBranch(mt)
439 # Go back to maint to create some more there
440 checkoutBranch(mt)
441 createLinearHistory(n, start=3, count=1)
443 # Now let's go back and fix that one commit
444 checkoutRelease(2)
445 createBranch(h)
446 createLinearHistory(r, createFile=True, count=1)
448 # Go back to maint, and merge it in
449 checkoutBranch(mt)
450 mergeBranch(h)
452 # Now we can create the last bit of history here
453 createLinearHistory(n, start=4, count=3)
455 # Now we can create our last bit of history on master
456 checkoutBranch(m)
457 createLinearHistory(c, start=6, count=3)
459 return 0
461 def main(args):
462 """Creates a test and a metrics repository
464 Args:
465 args: An array of arguments, when 2 in size the second
466 element should either be 'test' to just create the test
467 repo, or 'metrics' to just create the metrics
468 repository. If both should be created then the size of
469 args should be 1. The first element in the array is
470 always ignored.
472 Returns: 0 upon success, or nonzero upon failure.
475 size = len(args)
477 if size > 1 and (args[1] != "test" and args[1] != "metrics") or size > 2:
478 print "Please specify either 'test', 'metrics', or nothing to run both"
479 return 1
481 if len(args) == 1 or args[1] == "test":
482 ret = createTestRepository()
483 if ret != 0:
484 return ret
486 if len(args) == 1 or args[1] == "metrics":
487 ret = createMetricsRepository()
488 if ret != 0:
489 return ret
491 return 0
493 if __name__ == '__main__':
494 import sys
495 ret = main(sys.argv)
496 sys.exit(ret)