|
1
|
/* |
|
2
|
** Copyright (c) 2007 Andreas Kupries |
|
3
|
** |
|
4
|
** This program is free software; you can redistribute it and/or |
|
5
|
** modify it under the terms of the GNU General Public |
|
6
|
** License version 2 as published by the Free Software Foundation. |
|
7
|
** |
|
8
|
** This program is distributed in the hope that it will be useful, |
|
9
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
11
|
** General Public License for more details. |
|
12
|
** |
|
13
|
** You should have received a copy of the GNU General Public |
|
14
|
** License along with this library; if not, write to the |
|
15
|
** Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
16
|
** Boston, MA 02111-1307, USA. |
|
17
|
** |
|
18
|
** Author contact information: |
|
19
|
** [email protected] |
|
20
|
** |
|
21
|
** |
|
22
|
******************************************************************************* |
|
23
|
** |
|
24
|
** This file contains code used to de- and reconstruct a repository |
|
25
|
** into and from an indicated directory. |
|
26
|
*/ |
|
27
|
#include "config.h" |
|
28
|
#include "construct.h" |
|
29
|
#include <assert.h> |
|
30
|
#include <sys/types.h> |
|
31
|
#include <dirent.h> |
|
32
|
|
|
33
|
/* This function recursively scans the directory hierarchy starting at |
|
34
|
** zOrigin and enters all found files into the repository. The uuid is |
|
35
|
** generated from the file contents, and not taken from the, possibly |
|
36
|
** modified, file name. While function is able to handle the directory |
|
37
|
** structure created by 'deconstruct' it can actually much more. |
|
38
|
*/ |
|
39
|
|
|
40
|
static int import_origin(const char* zOrigin){ |
|
41
|
DIR *d; |
|
42
|
int count = 0; |
|
43
|
const char *zFormat; |
|
44
|
const char *zDir = zOrigin; |
|
45
|
struct dirent *pEntry; |
|
46
|
|
|
47
|
if( zDir[0]==0 ){ |
|
48
|
zDir = "."; |
|
49
|
zFormat = "%s%s"; |
|
50
|
}else{ |
|
51
|
zFormat = "%s/%s"; |
|
52
|
} |
|
53
|
|
|
54
|
d = opendir(zDir); |
|
55
|
if( d ){ |
|
56
|
while( (pEntry=readdir(d))!=0 ){ |
|
57
|
char *zPath; |
|
58
|
if( pEntry->d_name[0]=='.' ) continue; |
|
59
|
zPath = mprintf(zFormat, zOrigin, pEntry->d_name); |
|
60
|
if( file_isdir(zPath)==1 ){ |
|
61
|
count += import_origin(zPath); |
|
62
|
}else if( file_isfile(zPath) ){ |
|
63
|
Blob zIn; |
|
64
|
blob_read_from_file (&zIn,zPath); |
|
65
|
content_put (&zIn, 0, 0); |
|
66
|
blob_reset (&zIn); |
|
67
|
count++; |
|
68
|
} |
|
69
|
free (zPath); |
|
70
|
} |
|
71
|
} |
|
72
|
closedir(d); |
|
73
|
return count; |
|
74
|
} |
|
75
|
|
|
76
|
/* |
|
77
|
** COMMAND: deconstruct |
|
78
|
** Usage %fossil deconstruct ?-R|--repository REPOSITORY? DESTINATION |
|
79
|
** |
|
80
|
** Populates the indicated DESTINATION directory with copies of all |
|
81
|
** artifcats contained within the repository. Artifacts are named AA/bbbbb |
|
82
|
** where AA is the first 2 characters of the artifact ID and bbbbb is the |
|
83
|
** remaining 38 characters. |
|
84
|
*/ |
|
85
|
|
|
86
|
void deconstruct_cmd(void){ |
|
87
|
const char* zDestination; |
|
88
|
Blob zOut; |
|
89
|
Stmt q; |
|
90
|
if( (g.argc != 3) && (g.argc != 5) ){ |
|
91
|
usage ("?-R|--repository REPOSITORY? DESTINATION"); |
|
92
|
} |
|
93
|
db_find_and_open_repository(1); |
|
94
|
zDestination = g.argv[g.argc-1]; |
|
95
|
if( !file_isdir (zDestination) ){ |
|
96
|
fossil_panic("not a directory: %s", zDestination); |
|
97
|
} |
|
98
|
/* Iterate over all blobs in the repository, retrieve their |
|
99
|
* contents, and write them to a file with a name based on their |
|
100
|
* uuid. Note: Non-writable destination causes bail-out in the first |
|
101
|
* call of blob_write_to_file. |
|
102
|
*/ |
|
103
|
db_prepare(&q, "SELECT rid,uuid FROM blob"); |
|
104
|
while( db_step(&q)==SQLITE_ROW ){ |
|
105
|
int rid = db_column_int (&q, 0); |
|
106
|
const char *zUuid = db_column_text(&q, 1); |
|
107
|
char *zFile = mprintf ("%s/%.2s/%s", zDestination, zUuid, zUuid + 2); |
|
108
|
content_get (rid,&zOut); |
|
109
|
blob_write_to_file (&zOut,zFile); |
|
110
|
blob_reset (&zOut); |
|
111
|
free(zFile); |
|
112
|
} |
|
113
|
db_finalize(&q); |
|
114
|
} |
|
115
|
|
|
116
|
/* |
|
117
|
** COMMAND: reconstruct |
|
118
|
** Usage %fossil reconstruct REPOSITORY ORIGIN |
|
119
|
** |
|
120
|
** Creates the REPOSITORY and populates it with the artifacts in the |
|
121
|
** indicated ORIGIN directory. |
|
122
|
*/ |
|
123
|
|
|
124
|
void reconstruct_cmd(void){ |
|
125
|
const char* zOrigin; |
|
126
|
const char* zRepository; |
|
127
|
int fileCnt; |
|
128
|
int errCnt; |
|
129
|
|
|
130
|
if( g.argc != 4 ){ |
|
131
|
usage ("REPOSITORY ORIGIN"); |
|
132
|
} |
|
133
|
zRepository = g.argv[2]; |
|
134
|
zOrigin = g.argv[3]; |
|
135
|
if( !file_isdir (zOrigin) ){ |
|
136
|
fossil_panic("not a directory: %s", zOrigin); |
|
137
|
} |
|
138
|
|
|
139
|
/* Create the foundation */ |
|
140
|
db_create_repository(zRepository); |
|
141
|
db_open_repository(zRepository); |
|
142
|
db_open_config(0); |
|
143
|
db_begin_transaction(); |
|
144
|
|
|
145
|
db_initial_setup(0, 0, 1); |
|
146
|
|
|
147
|
printf("project-id: %s\n", db_get("project-code", 0)); |
|
148
|
printf("server-id: %s\n", db_get("server-code", 0)); |
|
149
|
printf("admin-user: %s (no password set yet!)\n", g.zLogin); |
|
150
|
printf("baseline: %s\n", db_text(0, "SELECT uuid FROM blob")); |
|
151
|
|
|
152
|
/* Scan origin and insert all files found inside */ |
|
153
|
fileCnt = import_origin (zOrigin); |
|
154
|
|
|
155
|
printf("imported: %d %s\n", fileCnt, fileCnt == 1 ? |
|
156
|
"file" : "files"); |
|
157
|
|
|
158
|
/* Finalize the repository, rebuild the derived tables */ |
|
159
|
errCnt = rebuild_db(0, 0); |
|
160
|
|
|
161
|
if( errCnt ){ |
|
162
|
printf("%d %s. Rolling back changes.\n", errCnt, errCnt == 1 ? |
|
163
|
"error" : "errors"); |
|
164
|
db_end_transaction(1); |
|
165
|
}else{ |
|
166
|
db_end_transaction(0); |
|
167
|
} |
|
168
|
} |
|
169
|
|