@@ -24,10 +24,12 @@ Format of STDIN stream:
24
24
commit_msg
25
25
('from' sp committish lf)?
26
26
('merge' sp committish lf)*
27
- file_change*
27
+ ( file_change | ls) *
28
28
lf?;
29
29
commit_msg ::= data;
30
30
31
+ ls ::= 'ls' sp '"' quoted(path) '"' lf;
32
+
31
33
file_change ::= file_clr
32
34
| file_del
33
35
| file_rnm
@@ -132,7 +134,7 @@ Format of STDIN stream:
132
134
ts ::= # time since the epoch in seconds, ascii base10 notation;
133
135
tz ::= # GIT style timezone;
134
136
135
- # note: comments and cat requests may appear anywhere
137
+ # note: comments, ls and cat requests may appear anywhere
136
138
# in the input, except within a data command. Any form
137
139
# of the data command always escapes the related input
138
140
# from comment processing.
@@ -141,7 +143,9 @@ Format of STDIN stream:
141
143
# must be the first character on that line (an lf
142
144
# preceded it).
143
145
#
146
+
144
147
cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf;
148
+ ls_tree ::= 'ls' sp (hexsha1 | idnum) sp path_str lf;
145
149
146
150
comment ::= '#' not_lf* lf;
147
151
not_lf ::= # Any byte that is not ASCII newline (LF);
@@ -374,6 +378,7 @@ static int cat_blob_fd = STDOUT_FILENO;
374
378
375
379
static void parse_argv (void );
376
380
static void parse_cat_blob (void );
381
+ static void parse_ls (struct branch * b );
377
382
378
383
static void write_branch_report (FILE * rpt , struct branch * b )
379
384
{
@@ -2614,6 +2619,8 @@ static void parse_new_commit(void)
2614
2619
note_change_n (b , prev_fanout );
2615
2620
else if (!strcmp ("deleteall" , command_buf .buf ))
2616
2621
file_change_deleteall (b );
2622
+ else if (!prefixcmp (command_buf .buf , "ls " ))
2623
+ parse_ls (b );
2617
2624
else {
2618
2625
unread_command_buf = 1 ;
2619
2626
break ;
@@ -2837,6 +2844,153 @@ static void parse_cat_blob(void)
2837
2844
cat_blob (oe , sha1 );
2838
2845
}
2839
2846
2847
+ static struct object_entry * dereference (struct object_entry * oe ,
2848
+ unsigned char sha1 [20 ])
2849
+ {
2850
+ unsigned long size ;
2851
+ char * buf = NULL ;
2852
+ if (!oe ) {
2853
+ enum object_type type = sha1_object_info (sha1 , NULL );
2854
+ if (type < 0 )
2855
+ die ("object not found: %s" , sha1_to_hex (sha1 ));
2856
+ /* cache it! */
2857
+ oe = insert_object (sha1 );
2858
+ oe -> type = type ;
2859
+ oe -> pack_id = MAX_PACK_ID ;
2860
+ oe -> idx .offset = 1 ;
2861
+ }
2862
+ switch (oe -> type ) {
2863
+ case OBJ_TREE : /* easy case. */
2864
+ return oe ;
2865
+ case OBJ_COMMIT :
2866
+ case OBJ_TAG :
2867
+ break ;
2868
+ default :
2869
+ die ("Not a treeish: %s" , command_buf .buf );
2870
+ }
2871
+
2872
+ if (oe -> pack_id != MAX_PACK_ID ) { /* in a pack being written */
2873
+ buf = gfi_unpack_entry (oe , & size );
2874
+ } else {
2875
+ enum object_type unused ;
2876
+ buf = read_sha1_file (sha1 , & unused , & size );
2877
+ }
2878
+ if (!buf )
2879
+ die ("Can't load object %s" , sha1_to_hex (sha1 ));
2880
+
2881
+ /* Peel one layer. */
2882
+ switch (oe -> type ) {
2883
+ case OBJ_TAG :
2884
+ if (size < 40 + strlen ("object " ) ||
2885
+ get_sha1_hex (buf + strlen ("object " ), sha1 ))
2886
+ die ("Invalid SHA1 in tag: %s" , command_buf .buf );
2887
+ break ;
2888
+ case OBJ_COMMIT :
2889
+ if (size < 40 + strlen ("tree " ) ||
2890
+ get_sha1_hex (buf + strlen ("tree " ), sha1 ))
2891
+ die ("Invalid SHA1 in commit: %s" , command_buf .buf );
2892
+ }
2893
+
2894
+ free (buf );
2895
+ return find_object (sha1 );
2896
+ }
2897
+
2898
+ static struct object_entry * parse_treeish_dataref (const char * * p )
2899
+ {
2900
+ unsigned char sha1 [20 ];
2901
+ struct object_entry * e ;
2902
+
2903
+ if (* * p == ':' ) { /* <mark> */
2904
+ char * endptr ;
2905
+ e = find_mark (strtoumax (* p + 1 , & endptr , 10 ));
2906
+ if (endptr == * p + 1 )
2907
+ die ("Invalid mark: %s" , command_buf .buf );
2908
+ if (!e )
2909
+ die ("Unknown mark: %s" , command_buf .buf );
2910
+ * p = endptr ;
2911
+ hashcpy (sha1 , e -> idx .sha1 );
2912
+ } else { /* <sha1> */
2913
+ if (get_sha1_hex (* p , sha1 ))
2914
+ die ("Invalid SHA1: %s" , command_buf .buf );
2915
+ e = find_object (sha1 );
2916
+ * p += 40 ;
2917
+ }
2918
+
2919
+ while (!e || e -> type != OBJ_TREE )
2920
+ e = dereference (e , sha1 );
2921
+ return e ;
2922
+ }
2923
+
2924
+ static void print_ls (int mode , const unsigned char * sha1 , const char * path )
2925
+ {
2926
+ static struct strbuf line = STRBUF_INIT ;
2927
+
2928
+ /* See show_tree(). */
2929
+ const char * type =
2930
+ S_ISGITLINK (mode ) ? commit_type :
2931
+ S_ISDIR (mode ) ? tree_type :
2932
+ blob_type ;
2933
+
2934
+ if (!mode ) {
2935
+ /* missing SP path LF */
2936
+ strbuf_reset (& line );
2937
+ strbuf_addstr (& line , "missing " );
2938
+ quote_c_style (path , & line , NULL , 0 );
2939
+ strbuf_addch (& line , '\n' );
2940
+ } else {
2941
+ /* mode SP type SP object_name TAB path LF */
2942
+ strbuf_reset (& line );
2943
+ strbuf_addf (& line , "%06o %s %s\t" ,
2944
+ mode , type , sha1_to_hex (sha1 ));
2945
+ quote_c_style (path , & line , NULL , 0 );
2946
+ strbuf_addch (& line , '\n' );
2947
+ }
2948
+ cat_blob_write (line .buf , line .len );
2949
+ }
2950
+
2951
+ static void parse_ls (struct branch * b )
2952
+ {
2953
+ const char * p ;
2954
+ struct tree_entry * root = NULL ;
2955
+ struct tree_entry leaf = {0 };
2956
+
2957
+ /* ls SP (<treeish> SP)? <path> */
2958
+ p = command_buf .buf + strlen ("ls " );
2959
+ if (* p == '"' ) {
2960
+ if (!b )
2961
+ die ("Not in a commit: %s" , command_buf .buf );
2962
+ root = & b -> branch_tree ;
2963
+ } else {
2964
+ struct object_entry * e = parse_treeish_dataref (& p );
2965
+ root = new_tree_entry ();
2966
+ hashcpy (root -> versions [1 ].sha1 , e -> idx .sha1 );
2967
+ load_tree (root );
2968
+ if (* p ++ != ' ' )
2969
+ die ("Missing space after tree-ish: %s" , command_buf .buf );
2970
+ }
2971
+ if (* p == '"' ) {
2972
+ static struct strbuf uq = STRBUF_INIT ;
2973
+ const char * endp ;
2974
+ strbuf_reset (& uq );
2975
+ if (unquote_c_style (& uq , p , & endp ))
2976
+ die ("Invalid path: %s" , command_buf .buf );
2977
+ if (* endp )
2978
+ die ("Garbage after path in: %s" , command_buf .buf );
2979
+ p = uq .buf ;
2980
+ }
2981
+ tree_content_get (root , p , & leaf );
2982
+ /*
2983
+ * A directory in preparation would have a sha1 of zero
2984
+ * until it is saved. Save, for simplicity.
2985
+ */
2986
+ if (S_ISDIR (leaf .versions [1 ].mode ))
2987
+ store_tree (& leaf );
2988
+
2989
+ print_ls (leaf .versions [1 ].mode , leaf .versions [1 ].sha1 , p );
2990
+ if (!b || root != & b -> branch_tree )
2991
+ release_tree_entry (root );
2992
+ }
2993
+
2840
2994
static void checkpoint (void )
2841
2995
{
2842
2996
checkpoint_requested = 0 ;
@@ -3001,7 +3155,7 @@ static int parse_one_feature(const char *feature, int from_stream)
3001
3155
relative_marks_paths = 0 ;
3002
3156
} else if (!prefixcmp (feature , "force" )) {
3003
3157
force_update = 1 ;
3004
- } else if (!strcmp (feature , "notes" )) {
3158
+ } else if (!strcmp (feature , "notes" ) || ! strcmp ( feature , "ls" ) ) {
3005
3159
; /* do nothing; we have the feature */
3006
3160
} else {
3007
3161
return 0 ;
@@ -3142,6 +3296,8 @@ int main(int argc, const char **argv)
3142
3296
while (read_next_command () != EOF ) {
3143
3297
if (!strcmp ("blob" , command_buf .buf ))
3144
3298
parse_new_blob ();
3299
+ else if (!prefixcmp (command_buf .buf , "ls " ))
3300
+ parse_ls (NULL );
3145
3301
else if (!prefixcmp (command_buf .buf , "commit " ))
3146
3302
parse_new_commit ();
3147
3303
else if (!prefixcmp (command_buf .buf , "tag " ))
0 commit comments