git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Index format v5

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
May 14, 2012, 21:08 UTC
Message-ID
<4FB1746A.6090408@alum.mit.edu>
In-Reply-To
<20120514150113.GD2107@tgummerer>
On 05/14/2012 05:01 PM, Thomas Gummerer wrote:
> Thanks a lot for your feedback. I've now refactored the code and
> thanks to your suggestions hopefully made it simpler and easier
> to read. The reader should now read exactly the data from the
> spec.
Yes, the style is much better now.  Here is the next round of feedback:
1. f is still a global variable.  This is unnecessary.
2. read_name() is indented incorrectly.
3. The signature and version number should be checked within 
read_header() *before* reading anything else.  Otherwise, if some random 
file is given to the script, it will read some random, probably very 
large number for "nextensions" and then try to read that number of 
extension offsets into RAM.  It would be a pretty innocent error to have 
the wrong version of the index file lying around, and the script should 
detect such an error quickly and painlessly rather than triggering a lot 
of pointless disk activity (and likely an out-of-memory error) before 
figuring out that it shouldn't be reading the file in the first place.
4. For readability reasons, it is better to raise an exception 
immediately in an error situation rather than put the error-handling 
code in the "else" part of an if statement; i.e., instead of
     if not error_condition:
         non-error-actions
     else:
         raise exception
use
     if error_condition:
         raise exception
     non-error-actions

The reasons are: (a) the reader can see immediately what will happen in the error case, then forget it and continue on with the "normal" flow instead of having to remember the "if" condition through the whole long "then" block before finally seeing the point in the "else" block; (b) then the "normal" case doesn't have to be within the if statement at all, thereby requiring less block nesting and less indentation. For example:

Show 10 quoted lines
> -    if crc == datacrc:
> -        return dict(signature=signature, vnr=vnr, ndir=ndir, nfile=nfile,
> -                nextensions=nextensions, extoffsets=extoffsets)
> -    else:
> -        raise Exception("Wrong header crc")
> +    if crc != datacrc:
> +        raise Exception("Wrong header crc")
> +
> +    return dict(signature=signature, vnr=vnr, ndir=ndir, nfile=nfile,
> +                nextensions=nextensions, extoffsets=extoffsets)
5. If the first limit of a range() or xrange() is zero, it is usually 
omitted; e.g., "xrange(0, nextensions)" -> "xrange(nextensions)".
6. It is possible to precompile "struct" patterns, which should be 
faster and also allows you to ask the Struct object its size, reducing 
the number of magic numbers needed in the code.  And fixed-length 
strings can also be read via struct.  For example:
Show 12 quoted lines
> DIR_DATA_STRUCT = struct.Struct("!HIIIIII 20s")
>
>
> def read_dirs(f, ndir):
>     dirs = list()
>     for i in xrange(0, ndir):
>         (pathname, partialcrc) = read_name(f)
>
>         (filedata, partialcrc) = read_calc_crc(f, DIR_DATA_STRUCT.size, partialcrc)
>         (flags, foffset, cr, ncr, nsubtrees, nfiles,
>                 nentries, objname) = DIR_DATA_STRUCT.unpack(filedata)
>     # ...
7. The "if dirnr == 0" stuff in read_files() should probably be done in 
read_index_entries() (the first invocation is the only place dirnr==0, 
right?)
8. read_files() only returns a result "if len(directories) > dirnr". 
But actually I don't see the purpose for the check.  Earlier in the 
function you dereference directories[dirnr] several times, so it *must* 
be that dirnr < len(directories).  I think you can take out this test 
and unindent its block.
9. read_files() doesn't need to return "entries".  Since entries is an 
array that is only mutated in place, the return value will always be the 
same as the "entries" argument (albeit fuller).
10. It would make sense to extract a function read_file(), which reads a 
single file entry from the current position in the current file (using 
code from read_files()).  Similarly for read_dir()/read_dirs().
11. It is good form to move the file-level code into a main() function, 
then call that from the bottom of the file, something like this:
 > def main(args):
 >     ....
 >
 > main(sys.argv[1:])

This avoids creating global variables that are accidentally used within functions.

What is your plan for testing this code, and later the C version? For example, you might want to have a suite of index files with various contents, and compare the "git ls-files --debug" output with the output that is expected. How would you create index files like this? Via git commands? Or should one of your Python scripts be taught how to do it?

To make testing easier, you probably don't want to hard-code the name of the input file in git-read-index-v5.py, so that you can use it to read arbitrary files. For example, you might want to honor the GIT_INDEX_FILES environment variable in some form, or to take the name of the index file as a command-line argument.

Michael
-- 
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/
Previous: Thomas GummererNext: Thomas Rast
Message 36 of 49 in “Index format v5”
  1. Thomas GummererMay 3, 2012
  2. Thomas RastMay 3, 2012
  3. Junio C HamanoMay 3, 2012
  4. Michael HaggertyMay 4, 2012
  5. Robin RosenbergMay 7, 2012
  6. Ronan KeryellMay 3, 2012
  7. Thomas GummererMay 3, 2012
  8. Junio C HamanoMay 3, 2012
  9. Thomas RastMay 3, 2012
  10. Thomas RastMay 3, 2012
  11. Thomas RastMay 3, 2012
  12. Junio C HamanoMay 3, 2012
  13. Thomas GummererMay 3, 2012
  14. Robin RosenbergMay 7, 2012
  15. solo-git@goeswhere.comMay 3, 2012
  16. Nguyen Thai Ngoc DuyMay 4, 2012
  17. Thomas GummererMay 4, 2012
  18. Philip OakleyMay 4, 2012
  19. Junio C HamanoMay 4, 2012
  20. Nguyen Thai Ngoc DuyMay 6, 2012
  21. Thomas GummererMay 7, 2012
  22. Phil HordMay 6, 2012
  23. Thomas GummererMay 7, 2012
  24. Michael HaggertyMay 7, 2012
  25. Thomas GummererMay 8, 2012
  26. Nguyen Thai Ngoc DuyMay 8, 2012
  27. Nguyen Thai Ngoc DuyMay 8, 2012
  28. Thomas GummererMay 10, 2012
  29. Nguyen Thai Ngoc DuyMay 10, 2012
  30. Michael HaggertyMay 9, 2012
  31. Thomas GummererMay 10, 2012
  32. Michael HaggertyMay 10, 2012
  33. Thomas GummererMay 11, 2012
  34. Michael HaggertyMay 13, 2012
  35. Thomas GummererMay 14, 2012
  36. Michael HaggertyMay 14, 2012
  37. Thomas RastMay 14, 2012
  38. Michael HaggertyMay 15, 2012
  39. Thomas GummererMay 15, 2012
  40. Michael HaggertyMay 15, 2012
  41. Thomas GummererMay 18, 2012
  42. Michael HaggertyMay 19, 2012
  43. Thomas GummererMay 21, 2012
  44. Michael HaggertyMay 16, 2012
  45. Thomas GummererMay 16, 2012
  46. Michael HaggertyMay 19, 2012
  47. Thomas GummererMay 21, 2012
  48. Philip OakleyMay 13, 2012
  49. Thomas GummererMay 14, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.