💾 Archived View for 80h.dev › projects › gemgit › files › src › main.rs.gemini captured on 2020-09-24 at 00:47:18. Gemini links have been rewritten to link to archived content

View Raw

More Information

➡️ Next capture (2022-03-01)

-=-=-=-=-=-=-

01 extern crate structopt;

02 #[macro_use]

03 extern crate structopt_derive;

04

05 use std::path;

06 use std::fs::File;

07 use std::io;

08 use std::fs;

09 use std::str;

10 use std::io::Write;

11 use std::io::BufRead;

12 use structopt::StructOpt;

13 use git2::{DiffFormat, Repository};

14 use chrono::{TimeZone, Utc};

15

16 #[macro_use]

17 extern crate serde_derive;

18 extern crate toml;

19

20 #[derive(Debug, Deserialize, Clone)]

21 struct Gitdesc {

22 name: String,

23 url: String,

24 desc: String,

25 readme: String,

26 }

27

28 fn gitdesc(file: path::PathBuf) -> Result<Gitdesc, io::Error> {

29 let fd = std::fs::read_to_string(file)?;

30 let gd: Gitdesc = toml::from_str(&fd)?;

31 return Ok(gd)

32 }

33

34 #[derive(StructOpt, Debug)]

35 #[structopt(name = "example", about = "An example of StructOpt usage.")]

36 struct Args {

37 #[structopt(short = "d", long = "dir", help = "Git dir")]

38 dir: String,

39 #[structopt(short = "o", long = "out", help = "Out dir")]

40 out: String,

41 }

42

43 fn read_file(file: &path::Path) -> io::Result<String> {

44 let fd = std::fs::File::open(&file)?;

45 let buf = io::BufReader::new(fd);

46 let mut s = String::new();

47 let mut n = 1;

48 for line in buf.lines() {

49 if let Ok(l) = line {

50 s.push_str(&format!("{:02} {}\n", n, l));

51 n += 1;

52 }

53 }

54 return Ok(s);

55 }

56

57 fn write_file(file: path::PathBuf, out: String) -> io::Result<()> {

58 let mut fd = File::create(file)?;

59 write!(fd, "{}", out)?;

60 Ok(())

61 }

62

63 fn files_index(mut path: path::PathBuf) -> io::Result<()> {

64 let mut idx = String::from(format!("# Files\n\nPath: {}\n\n", &path.display()));

65 for entry in std::fs::read_dir(&path)? {

66 if let Ok(entry) = entry {

67 let m = entry.metadata()?;

68 let p = entry.path();

69 let entry = p.strip_prefix(&path).unwrap();

70 if m.is_dir() {

71 idx.push_str(&format!("=> {}/ {}/\n", entry.display(), entry.display()));

72 files_index(p.to_path_buf())?;

73 } else {

74 let file = entry.to_str().unwrap().trim_end_matches(".gemini");

75 idx.push_str(&format!("=> {} {}\n", entry.display(), file));

76 }

77 }

78 }

79 path.push("index.gemini");

80 write_file(path,idx)?;

81 Ok(())

82 }

83

84 fn walk_dir(from: path::PathBuf, dst: path::PathBuf) -> io::Result<()> {

85 for entry in std::fs::read_dir(&from)? {

86 let entry = entry?;

87 if entry.file_name().to_str().unwrap().starts_with(".") {

88 continue;

89 }

90 let m = entry.metadata()?;

91 let mut dst = dst.clone();

92 let mut from = from.clone();

93 let p = entry.path();

94 let s = read_file(&p)?;

95 let p = p.strip_prefix(&from).unwrap();

96 if m.is_dir() {

97 if entry.path() == from {

98 continue;

99 }

100 dst.push(p);

101 from.push(p);

102 std::fs::create_dir_all(&dst)?;

103 walk_dir(from, dst)?;

104 continue

105 }

106 dst.push(format!("{}.gemini", p.display()));

107 write_file(dst, s)?;

108 }

109 Ok(())

110 }

111

112 fn commit_to_string(commit: git2::Commit) -> String {

113 let tm = commit.time().seconds();

114 let tm = Utc.timestamp(tm, 0);

115 let mut cm = commit.message().unwrap().trim().to_string();

116 if cm.len() >= 30 {

117 cm.truncate(29);

118 cm.push_str("…");

119 }

120 let s = String::from(format!("\n=> {}.txt {} {:<30} {}\n",

121 commit.id(),

122 tm.format("%Y-%m-%d %H:%M").to_string(),

123 cm,

124 commit.author()));

125 return s;

126 }

127

128 fn commits(mut pout: path::PathBuf, repo: Repository) -> Result<i64, git2::Error> {

129 let mut revwalk = repo.revwalk()?;

130 revwalk.push_head()?;

131 let mut com = String::from(format!("Date {:>26} {:>23}", "Commit Message","Author\n"));

132 let mut num: i64 = 0;

133

134 for id in revwalk {

135 let id = id?;

136 let commit = repo.find_commit(id)?;

137 let mut p = pout.clone();

138 p.push(format!("{}.txt",id));

139

140 let a = if commit.parents().len() == 1 {

141 let parent = commit.parent(0)?;

142 Some(parent.tree()?)

143 } else {

144 None

145 };

146 let b = commit.tree()?;

147 let mut d = String::new();

148 d.push_str(&format!("Commit: {}\nMessage:\n{}\n", id, commit.message().unwrap()));

149 let diff = repo.diff_tree_to_tree(a.as_ref(), Some(&b), None)?;

150 diff.print(DiffFormat::Patch, |_delta, _hunk, line| {

151 match line.origin() {

152 ' ' | '+' | '-' => d.push_str(&format!("{}", line.origin())),

153 _ => {}

154 }

155 d.push_str(&format!("{}", str::from_utf8(line.content()).unwrap()));

156 true

157 })?;

158 p.set_file_name(format!("{}.txt", id));

159 write_file(p, d).expect("Couldn't write file");

160 com.push_str(&commit_to_string(commit));

161 num += 1;

162 }

163

164 pout.push("index.gemini");

165 write_file(pout, com).expect("Couldn't write to file");

166 Ok(num)

167 }

168

169 fn index(path: path::PathBuf, gd: Gitdesc, num: i64) -> Result<String, io::Error> {

170 let mut index = String::from(format!(

171 "=== {} ===\n{}

172 \nClone the repo with: git clone {}\n

173 \n=== Git Details ===

174 \n=> commits/ View {} commits

175 \n=> files/ Files\n

176 \n=== Readme ===\n", gd.name, gd.desc, gd.url, num));

177

178 let readme = fs::read_to_string(path)?;

179 index.push_str(&readme);

180

181

182 Ok(index)

183 }

184

185 fn main() -> Result<(), io::Error> {

186 let args = Args::from_args();

187 let mut gpath = path::PathBuf::from(args.dir);

188 let gd = gpath.join(".gemgit");

189 let gd = gitdesc(gd)?;

190 let mut out = path::PathBuf::from(args.out);

191

192 let repo = Repository::open(&gpath).expect("Can't open repo");

193

194 out.push("commits/");

195 if !out.exists() {

196 std::fs::create_dir_all(&out)?;

197 }

198

199 let num = commits(out.clone(), repo).unwrap();

200 out.pop();

201

202 gpath.push(&gd.readme);

203 let idx = index(gpath.clone(), gd, num)?;

204 gpath.pop();

205

206 out.push("index.gemini");

207 write_file(out.clone(), idx)?;

208 out.pop();

209

210 out.push("files");

211 if !out.exists() {

212 std::fs::create_dir_all(&out)?;

213 }

214 walk_dir(gpath, out.clone())?;

215 files_index(out)?;

216

217 Ok(())

218 }