export-to-git._pike
Go to the documentation of this file.
1 /* Copyright (C) 2000-2004 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  * Copyright (C) 2003-2010 Martin Baehr
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * $Id: debug.pike.in,v 1.1 2009/09/28 14:19:52 nicke Exp $
19  */
20 inherit .client;
21 #include "/usr/local/lib/steam/server/include/classes.h"
22 class export-to-git {
23 public:
24 
25 
26 
27 #define OBJ(o) _Server->get_module("filepath:tree")->path_to_object(o)
28 
29 
30 array history = ({});
31 object _Server;
32 
33 void git_object(object obj, string to)
34 {
35  if (obj->get_object_class() & CLASS_DOCUMENT)
36  {
37  mapping versions = obj->query_attribute("DOC_VERSIONS");
38  string path = obj->query_attribute("OBJ_PATH");
39  int flag=0;
40  if (!sizeof(versions))
41  {
42  flag=1;
43  versions = ([ 1:obj ]);
44  }
45 
46  array this_history = ({});
47  foreach(versions; int nr; object version)
48  {
49  this_history += ({ ([ "obj":version, "version":nr, "time":version->query_attribute("DOC_LAST_MODIFIED"), "path":obj->query_attribute("OBJ_PATH") ]) });
50  }
51  sort(this_history->version, this_history);
52  if(flag==0)
53  this_history += ({ ([ "obj":obj, "version":this_history[-1]->version+1, "time":obj->query_attribute("DOC_LAST_MODIFIED"), "path":obj->query_attribute("OBJ_PATH") ]) });
54 
55  int timestamp = 0;
56  string oldname;
57  foreach(this_history; int nr; mapping version)
58  {
59  string newname;
60  if (version->obj->query_attribute("OBJ_VERSIONOF"))
61  newname = version->obj->query_attribute("OBJ_VERSIONOF")->query_attribute("OBJ_NAME");
62  else
63  newname = version->obj->query_attribute("OBJ_NAME");
64  if (oldname && oldname != newname)
65  {
66  werror("rename %s -> %s\n", oldname, newname);
67  version->oldname = oldname;
68  }
69  oldname = newname;
70  version->name = newname;
71  if (timestamp > version->obj->query_attribute("DOC_LAST_MODIFIED"))
72  {
73  werror("timeshift! %d -> %d\n", timestamp, version->obj->query_attribute("DOC_LAST_MODIFIED"));
74  }
75  }
76  history += this_history;
77  }
78  //THIS IS FOR CREATING THE FOLDERS. NEED TO DISABLE IT WITH NO PATH OPTION
79  string tocreate;
80  string from = options->src;
81  if(from[-1]=='/'&&sizeof(from)!=1)
82  from = from[ ..sizeof(from)-2];
83  if(from=="/")
84  options->nopath=0;
85  if(options->nopath)
86  {
87  string temppath = obj->query_attribute("OBJ_PATH");
88  string tempclass = OBJ(from)->get_class();
89 
90  if(sizeof(temppath)>0 && temppath[-1]=='/')
91  temppath = temppath[ ..sizeof(temppath)-2];
92  int s =sizeof((from/"/")-({""}));
93  if(tempclass!="Container" && tempclass!="Room")
94  s=s-1;
95  array temp = (temppath/"/") - ({""});
96  tocreate = to+"/"+(temp[s..]*"/");
97  }
98  else
99  tocreate = to+obj->query_attribute("OBJ_PATH");
100 
101  if (obj->get_object_class() & CLASS_CONTAINER && obj->query_attribute("OBJ_PATH") != "/home")
102  {
103 
104  string objname="";
105  string base = basename(from);
106  mixed error = catch {
107  objname = obj->query_attribute("OBJ_NAME");
108  };
109  if((options->nopath&&!(objname[0 .. sizeof(base)]==base))||!options->nopath)
110  {
111  mkdir(tocreate); //CHANGE changed path to name here
112  }
113  foreach(obj->get_inventory();; object cont)
114  {
115  if(!(obj->get_object_class() & CLASS_USER))
116  git_object(cont, to);
117  }
118  }
119 }
120 
121 void git_add(mapping doc, string to)
122 {
123  string from = options->src;
124  string content = doc->obj->get_content();
125  if (!content)
126  return;
127  string actual;
128  if(to[-1]=='/')
129  to = to[ ..sizeof(to)-2];
130  //Checks whether there is a / at the end of to, if yes first one writes otherwise second one writes
131  if(options->nopath)
132  {
133  string temppath = doc->path;
134  string tempclass = OBJ(from)->get_class();
135  if(temppath[-1]=='/')
136  temppath = temppath[ ..sizeof(temppath)-2];
137  int s =sizeof((from/"/")-({""}));
138  if(tempclass!="Container" && tempclass!="Room")
139  s=s-1;
140  array temp = (temppath/"/") - ({""});
141  string tocreate =to+"/"+(temp[s..]*"/");
142  Stdio.write_file(tocreate, content); //changed doc->name from /home/coder/demo1 to demo1
143  actual = (temp[s..]*"/"); //to+"/" not needed, as git add using path as to.
144  if(actual[0]=='/')
145  actual = actual[1..];
146  }
147  else
148  {
149  Stdio.write_file(to+doc->path, content);
150  actual = doc->path;
151  if(actual[0]=='/')
152  actual = actual[1..];
153  }
154  Process.create_process(({ "git", "add", actual }), ([ "cwd": to ]))->wait();
155 }
156 
157 string git_commit(string message, string to, string authorname, string authoremail, int time, int|void isempty)
158 {
159  Stdio.File output = Stdio.File();
160  write("committing: %s\n", message);
161  int errno;
162  string time_s = Calendar.Second("unix", time)->set_timezone("UTC")->format_nice();
163  errno = Process.create_process(({ "git", "commit", "--allow-empty", "-m", message }), ([ "env":([ "GIT_AUTHOR_NAME":authorname, "GIT_AUTHOR_EMAIL":authoremail, "GIT_AUTHOR_DATE":time_s, "GIT_COMMITTER_NAME":authorname, "GIT_COMMITTER_EMAIL":authoremail, "GIT_COMMITTER_DATE":time_s ]), "cwd":to , "stdout":output->pipe() ]))->wait();
164  output->read();
165  if (!errno)
166  {
167  Process.create_process(({ "git", "rev-parse", "HEAD" }), ([ "cwd": to, "stdout":output->pipe() ]))->wait();
168  write("Commit hash : "+output->read()+"\n");
169  return output->read()-"\n";
170  }
171  else
172  return "";
173 }
174 
175 void git_init(string dir)
176 {
177  dir_check("",dir);
178  if (Process.create_process(({ "git", "status" }), ([ "cwd":dir ]))->wait())
179  {
180  Process.create_process(({ "git", "init" }), ([ "cwd":dir ]))->wait();
181  write("Git Initialized\n\n");
182  }
183 }
184 
185 int main(int argc, array argv)
186 {
187  options=init(argv);
188  array opt = Getopt.find_all_options(argv,aggregate(
189  ({"update",Getopt.NO_ARG,({"-U","--update"})}),
190  ({"restart",Getopt.NO_ARG,({"-R","--restart"})}),
191  ({"nopath",Getopt.NO_ARG,({"-N","--no-path"})}),
192  ));
193  options += mkmapping(opt[*][0], opt[*][1]);
194  options->src = argv[-2];
195  options->dest = argv[-1];
196  _Server=conn->SteamObj(0);
197  export_to_git(OBJ(options->src), options->dest, ({ OBJ("/home") }));
198 }
199 
200 int count=0;
201 string dir_check(string def, string dir)
202 {
203  if(def!="")
204  {
205  int y=1;
206  array new = dir/"/";
207  string oclass = OBJ(dir)->get_class();
208  if(oclass=="Container"||oclass=="Room") //if its a container/room like /sources , then last element of new doesn't get discarded.
209  y=1;
210  else
211  y=2; //if it is a file like /sources/file , then file gets discarded because only sourced folder needs to be created
212  foreach(new[1..sizeof(new)-y] , string x)
213  {
214 
215  if (!Stdio.is_dir(def+"/"+x))
216  {
217  mkdir(def+"/"+x);
218  }
219  def = def+"/"+x;
220  }
221  if(oclass=="Container"||oclass=="Room")
222  return def;
223  return def+"/"+new[sizeof(new)-1]; //complete path to file or folder
224  }
225  else
226  {
227  array arr = dir/"/";
228  if(arr[-1] == "")
229  arr = arr[0 .. sizeof(arr)-2]; //last "/" should not be counted
230  array temp = arr;
231  int flag = 0;
232  int x = 0;
233  while (!Stdio.is_dir(temp*"/")) //checking what all directories need to be created
234  {
235  flag=1;
236  temp = temp[0 .. sizeof(temp)-2];
237  x = sizeof(temp);
238  }
239  while(!Stdio.is_dir(dir) && flag==1) //flag is 1 means some directories have to be created. this loop creates the directories one by one.
240  {
241  temp = temp + ({ arr[x] });
242  mkdir(temp*"/");
243  x++;
244  }
245  }
246  return "";
247 }
248 
249 void git_create_branch(string to)
250 {
251  string cur_time = replace(Calendar.now()->set_timezone("UTC")->format_nice(),([":":"-" , " ":"-"]));
252  Process.create_process(({ "git", "checkout", "--orphan", cur_time }), ([ "cwd": to ]))->wait();
253  Process.create_process(({ "git", "rm", "-rf", "."}),([ "cwd": to]))->wait();
254  dir_check("",to);
255 }
256 
257 void export_to_git(object from, string to, void|array exclude)
258 {
259  string complete_path;
260  git_init(to);
261  git_create_branch(to);
262  if(!options->nopath) // only if paths have to be created
263  complete_path = dir_check(to,options->src);
264  git_object(from, to);
265  write("Commit message : sTeam export-to-git\n");
266  git_commit("sTeam export-to-git", to, "root", "root@localhost", 0, 1); //empty commit
267  sort(history->time, history);
268  foreach(history;; mapping doc)
269  {
270  git_add(doc, to);
271  string message = sprintf("%s - %d - %d", doc->obj->get_identifier(), doc->obj->get_object_id(), doc->version);
272  write("Commit message : "+message+"\n");
273  object author = doc->obj->query_attribute("DOC_USER_MODIFIED")||doc->obj->query_attribute("OBJ_OWNER");
274  string author_username = "unknown";
275  if (author)
276  author_username = author->get_user_name();
277  string author_email = sprintf("%s@%s", author_username, _Server->get_server_name());
278  string hash = (string)git_commit(message, to, author->query_attribute("USER_FULLNAME"), author_email, doc->time);
279  }
280 }
281 
282 
283 };