1use chrono;
3use chrono::{DateTime, Utc};
4use flate2;
5use rand;
6use std::collections::{HashMap, HashSet};
7use std::fs::{metadata, File, OpenOptions};
8use std::io::{BufRead, Read, Write};
9use std::path::Path;
10use std::path::PathBuf;
11use std::rc::Rc;
12use std::str::from_utf8;
13use thrussh_keys;
14use thrussh_keys::key::KeyPair;
15use thrussh_keys::PublicKeyBase64;
16pub type Flag = u8;
17use bincode::{deserialize, deserialize_from, serialize};
18use bs58;
19use serde_json;
20use {ErrorKind, Result};
21
22bitflags! {
23 #[derive(Serialize, Deserialize)]
24 pub struct PatchFlags: u32 {
25 const TAG = 1;
26 }
27}
28
29#[derive(Debug, Serialize, Deserialize, Clone)]
31pub struct UnsignedPatch {
32 pub header: PatchHeader,
34 pub dependencies: HashSet<Hash>,
36 pub changes: Vec<Change<ChangeContext<Hash>>>,
38}
39
40#[derive(Debug, Serialize, Deserialize, Clone)]
42pub enum Patch {
43 Unsigned0,
44 Signed0,
45 Unsigned(UnsignedPatch),
46}
47
48impl Patch {
49 pub fn changes(&self) -> &[Change<ChangeContext<Hash>>] {
51 match *self {
52 Patch::Signed0 | Patch::Unsigned0 => {
53 panic!("refusing to interact with old patch version")
54 }
55 Patch::Unsigned(ref patch) => &patch.changes,
56 }
57 }
58 pub fn changes_mut(&mut self) -> &mut Vec<Change<ChangeContext<Hash>>> {
59 match *self {
60 Patch::Signed0 | Patch::Unsigned0 => {
61 panic!("refusing to interact with old patch version")
62 }
63 Patch::Unsigned(ref mut patch) => &mut patch.changes,
64 }
65 }
66 pub fn dependencies(&self) -> &HashSet<Hash> {
68 match *self {
69 Patch::Signed0 | Patch::Unsigned0 => {
70 panic!("refusing to interact with old patch version")
71 }
72 Patch::Unsigned(ref patch) => &patch.dependencies,
73 }
74 }
75 pub fn dependencies_mut(&mut self) -> &mut HashSet<Hash> {
76 match *self {
77 Patch::Signed0 | Patch::Unsigned0 => {
78 panic!("refusing to interact with old patch version")
79 }
80 Patch::Unsigned(ref mut patch) => &mut patch.dependencies,
81 }
82 }
83 pub fn header(&self) -> &PatchHeader {
85 match *self {
86 Patch::Signed0 | Patch::Unsigned0 => {
87 panic!("refusing to interact with old patch version")
88 }
89 Patch::Unsigned(ref patch) => &patch.header,
90 }
91 }
92 pub fn header_mut(&mut self) -> &mut PatchHeader {
93 match *self {
94 Patch::Signed0 | Patch::Unsigned0 => {
95 panic!("refusing to interact with old patch version")
96 }
97 Patch::Unsigned(ref mut patch) => &mut patch.header,
98 }
99 }
100
101 pub fn read_dependencies<R: Read>(mut r: R) -> Result<Vec<Hash>> {
103 let version: u32 = deserialize_from(&mut r)?;
104 assert_eq!(version, 2);
105 let _header: PatchHeader = deserialize_from(&mut r)?;
106 debug!("version: {:?}", version);
107 Ok(deserialize_from(&mut r)?)
108 }
109}
110
111#[derive(Debug, Serialize, Deserialize, Clone)]
114pub struct PatchHeader {
115 pub authors: Vec<String>,
116 pub name: String,
117 pub description: Option<String>,
118 pub timestamp: DateTime<Utc>,
119 pub flag: PatchFlags,
120}
121
122use std::ops::{Deref, DerefMut};
123impl Deref for Patch {
124 type Target = PatchHeader;
125 fn deref(&self) -> &Self::Target {
126 self.header()
127 }
128}
129impl DerefMut for Patch {
130 fn deref_mut(&mut self) -> &mut Self::Target {
131 self.header_mut()
132 }
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct NewEdge {
139 pub from: Key<Option<Hash>>,
140 pub to: Key<Option<Hash>>,
141 pub introduced_by: Option<Hash>,
142}
143
144pub type ChangeContext<H> = Vec<Key<Option<H>>>;
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub enum Change<Context> {
148 NewNodes {
149 up_context: Context,
150 down_context: Context,
151 flag: EdgeFlags,
152 line_num: LineId,
153 nodes: Vec<Vec<u8>>,
154 inode: Key<Option<Hash>>,
155 },
156 NewEdges {
157 previous: EdgeFlags,
158 flag: EdgeFlags,
159 edges: Vec<NewEdge>,
160 inode: Key<Option<Hash>>,
161 },
162}
163
164impl PatchHeader {
165 pub fn from_reader_nochanges<R: Read>(mut r: R) -> Result<PatchHeader> {
167 let version: u32 = deserialize_from(&mut r)?;
168 debug!("version: {:?}", version);
169 Ok(deserialize_from(&mut r)?)
170 }
171}
172
173#[derive(Debug)]
175pub enum Record<Context> {
176 FileMove {
177 new_name: String,
178 del: Change<Context>,
179 add: Change<Context>,
180 },
181 FileDel {
182 name: String,
183 del: Change<Context>,
184 },
185 FileAdd {
186 name: String,
187 add: Change<Context>,
188 },
189 Change {
190 file: Rc<PathBuf>,
191 change: Change<Context>,
192 conflict_reordering: Vec<Change<Context>>,
193 },
194 Replace {
195 file: Rc<PathBuf>,
196 adds: Change<Context>,
197 dels: Change<Context>,
198 conflict_reordering: Vec<Change<Context>>,
199 },
200}
201
202pub struct RecordIter<R, C> {
203 rec: Option<R>,
204 extra: Option<C>,
205}
206
207impl<Context> IntoIterator for Record<Context> {
208 type IntoIter = RecordIter<Record<Context>, Change<Context>>;
209 type Item = Change<Context>;
210 fn into_iter(self) -> Self::IntoIter {
211 RecordIter {
212 rec: Some(self),
213 extra: None,
214 }
215 }
216}
217
218impl<Context> Record<Context> {
219 pub fn iter(&self) -> RecordIter<&Record<Context>, &Change<Context>> {
220 RecordIter {
221 rec: Some(self),
222 extra: None,
223 }
224 }
225}
226
227impl<Context> Iterator for RecordIter<Record<Context>, Change<Context>> {
228 type Item = Change<Context>;
229 fn next(&mut self) -> Option<Self::Item> {
230 if let Some(extra) = self.extra.take() {
231 Some(extra)
232 } else if let Some(rec) = self.rec.take() {
233 match rec {
234 Record::FileMove { del, add, .. } => {
235 self.extra = Some(add);
236 Some(del)
237 }
238 Record::FileDel { del: c, .. }
239 | Record::FileAdd { add: c, .. }
240 | Record::Change { change: c, .. } => Some(c),
241 Record::Replace { adds, dels, .. } => {
242 self.extra = Some(adds);
243 Some(dels)
244 }
245 }
246 } else {
247 None
248 }
249 }
250}
251
252impl<'a, Context> Iterator for RecordIter<&'a Record<Context>, &'a Change<Context>> {
253 type Item = &'a Change<Context>;
254 fn next(&mut self) -> Option<Self::Item> {
255 if let Some(extra) = self.extra.take() {
256 Some(extra)
257 } else if let Some(rec) = self.rec.take() {
258 match *rec {
259 Record::FileMove {
260 ref del, ref add, ..
261 } => {
262 self.extra = Some(add);
263 Some(del)
264 }
265 Record::FileDel { del: ref c, .. }
266 | Record::FileAdd { add: ref c, .. }
267 | Record::Change { change: ref c, .. } => Some(c),
268 Record::Replace {
269 ref adds, ref dels, ..
270 } => {
271 self.extra = Some(adds);
272 Some(dels)
273 }
274 }
275 } else {
276 None
277 }
278 }
279}
280
281impl UnsignedPatch {
282 pub fn empty() -> Self {
283 UnsignedPatch {
284 header: PatchHeader {
285 authors: vec![],
286 name: "".to_string(),
287 description: None,
288 timestamp: chrono::Utc::now(),
289 flag: PatchFlags::empty(),
290 },
291 dependencies: HashSet::new(),
292 changes: vec![],
293 }
294 }
295 pub fn leave_unsigned(self) -> Patch {
296 Patch::Unsigned(self)
297 }
298
299 fn is_tag(&self) -> bool {
300 self.header.flag.contains(PatchFlags::TAG)
301 }
302
303 pub fn inverse(&self, hash: &Hash, changes: &mut Vec<Change<ChangeContext<Hash>>>) {
304 for ch in self.changes.iter() {
305 debug!("inverse {:?}", ch);
306 match *ch {
307 Change::NewNodes {
308 ref up_context,
309 flag,
310 line_num,
311 ref nodes,
312 ref inode,
313 ..
314 } => {
315 let edges = up_context
316 .iter()
317 .map(|up| NewEdge {
318 from: Key {
319 patch: match up.patch {
320 Some(ref h) => Some(h.clone()),
321 None => Some(hash.clone()),
322 },
323 line: up.line,
324 },
325 to: Key {
326 patch: Some(hash.clone()),
327 line: line_num,
328 },
329 introduced_by: Some(hash.clone()),
330 })
331 .chain((1..nodes.len()).map(|i| NewEdge {
332 from: Key {
333 patch: Some(hash.clone()),
334 line: line_num + (i - 1),
335 },
336 to: Key {
337 patch: Some(hash.clone()),
338 line: line_num + i,
339 },
340 introduced_by: Some(hash.clone()),
341 }))
342 .collect();
343 changes.push(Change::NewEdges {
344 edges,
345 inode: inode.clone(),
346 previous: flag,
347 flag: flag ^ EdgeFlags::DELETED_EDGE,
348 })
349 }
350 Change::NewEdges {
351 previous,
352 flag,
353 ref edges,
354 ref inode,
355 } => changes.push(Change::NewEdges {
356 previous: flag,
357 flag: previous,
358 inode: inode.clone(),
359 edges: edges
360 .iter()
361 .map(|e| NewEdge {
362 from: e.from.clone(),
363 to: e.to.clone(),
364 introduced_by: Some(hash.clone()),
365 })
366 .collect(),
367 }),
368 }
369 }
370 }
371}
372
373impl Patch {
374 pub fn size_upper_bound(&self) -> usize {
378 let mut size: usize = 1 << 15;
380 for c in self.changes().iter() {
381 match *c {
382 Change::NewNodes { ref nodes, .. } => {
383 size += nodes.iter().map(|x| x.len()).sum::<usize>();
384 size += nodes.len() * 2048 }
386 Change::NewEdges { ref edges, .. } => size += edges.len() * 2048,
387 }
388 }
389 size
390 }
391
392 pub fn is_tag(&self) -> bool {
393 match *self {
394 Patch::Unsigned(ref patch) => patch.is_tag(),
395 _ => false,
396 }
397 }
398
399 pub fn from_reader_compressed<R: BufRead>(r: &mut R) -> Result<(Hash, Vec<u8>, Patch)> {
403 let mut rr = flate2::bufread::GzDecoder::new(r);
404 let filename = {
405 let filename = if let Some(header) = rr.header() {
406 if let Some(filename) = header.filename() {
407 from_utf8(filename)?
408 } else {
409 return Err(ErrorKind::EOF.into());
410 }
411 } else {
412 return Err(ErrorKind::EOF.into());
413 };
414 if let Some(h) = Hash::from_base58(filename) {
415 h
416 } else {
417 return Err(ErrorKind::WrongHash.into());
418 }
419 };
420
421 let mut buf = Vec::new();
422 rr.read_to_end(&mut buf)?;
423
424 let patch: Patch = deserialize(&buf[..])?;
426 patch.check_hash(&buf, &filename)?;
427
428 Ok((filename, buf, patch))
429 }
430
431 fn check_hash(&self, buf: &[u8], filename: &Hash) -> Result<()> {
432 let buf = match *self {
433 Patch::Signed0 | Patch::Unsigned0 => {
434 panic!("refusing to interact with old patch version")
435 }
436 Patch::Unsigned(_) => buf,
437 };
438 let hash = Hash::of_slice(buf)?;
439 match (filename, &hash) {
440 (&Hash::Sha512(ref filename), &Hash::Sha512(ref hash))
441 if &filename.0[..] == &hash.0[..] =>
442 {
443 Ok(())
444 }
445 _ => Err(ErrorKind::WrongHash.into()),
446 }
447 }
448
449 pub fn to_buf(&self) -> Result<(Vec<u8>, Hash)> {
450 let buf = serialize(&self)?;
452 let hash = Hash::of_slice(&buf)?;
454 Ok((buf, hash))
455 }
456
457 pub fn save<P: AsRef<Path>>(&self, dir: P, key: Option<&KeyPair>) -> Result<Hash> {
459 let (buf, hash) = self.to_buf()?;
460 let h = hash.to_base58();
462 let mut path = dir.as_ref().join(&h);
463 path.set_extension("gz");
464 if metadata(&path).is_err() {
465 debug!("save, path {:?}", path);
466 let f = File::create(&path)?;
467 debug!("created");
468 let mut w = flate2::GzBuilder::new()
469 .filename(h.as_bytes())
470 .write(f, flate2::Compression::best());
471 w.write_all(&buf)?;
472 w.finish()?;
473 debug!("saved");
474 }
475
476 if let Some(key) = key {
477 path.set_extension("sig");
478 let mut file = OpenOptions::new()
479 .read(true)
480 .write(true)
481 .create(true)
482 .open(&path)?;
483
484 let mut signatures: SignatureFile =
485 serde_json::from_reader(&mut file).unwrap_or(SignatureFile {
486 hash: h,
487 signatures: HashMap::new(),
488 });
489 let signature = key.sign_detached(&hash.as_ref().to_binary())?;
490 let public_key = key.public_key_base64();
491 signatures
492 .signatures
493 .insert(public_key, bs58::encode(&signature.as_ref()).into_string());
494 serde_json::to_writer(&mut file, &signatures)?;
495 }
496 Ok(hash)
497 }
498
499 pub fn inverse(&self, hash: &Hash, changes: &mut Vec<Change<ChangeContext<Hash>>>) {
500 match *self {
501 Patch::Unsigned0 => panic!("Can't reverse old patches"),
502 Patch::Signed0 => panic!("Can't reverse old patches"),
503 Patch::Unsigned(ref u) => u.inverse(hash, changes),
504 }
505 }
506}
507
508#[derive(Debug, Serialize, Deserialize)]
509pub struct SignatureFile {
510 pub hash: String,
511 pub signatures: HashMap<String, String>,
512}
513
514pub fn read_signature_file(r: &mut Read) -> Result<SignatureFile> {
515 let signatures: SignatureFile = serde_json::from_reader(r)?;
516 for (key, sig) in signatures.signatures.iter() {
518 let k = thrussh_keys::parse_public_key_base64(&key)?;
519 let sig = bs58::decode(sig).into_vec()?;
520 if !k.verify_detached(signatures.hash.as_bytes(), &sig) {
521 return Err(ErrorKind::WrongPatchSignature.into());
522 }
523 }
524 Ok(signatures)
525}
526
527impl SignatureFile {
528 pub fn write_signature_file(&self, w: &mut Write) -> Result<()> {
529 serde_json::to_writer(w, self)?;
530 Ok(())
531 }
532}
533
534pub struct Signatures<'a, R: Read>(
535 serde_json::StreamDeserializer<'a, serde_json::de::IoRead<R>, SignatureFile>,
536);
537
538pub fn read_signatures<'a, R: Read>(r: R) -> Signatures<'a, R> {
539 Signatures(serde_json::Deserializer::from_reader(r).into_iter())
540}
541
542impl<'a, R: Read> Iterator for Signatures<'a, R> {
543 type Item = Result<SignatureFile>;
544 fn next(&mut self) -> Option<Self::Item> {
545 self.0.next().map(|n| n.map_err(super::Error::from))
546 }
547}
548
549pub fn read_changes(r: &mut Read) -> Result<HashMap<Hash, ApplyTimestamp>> {
550 let mut s = String::new();
551 r.read_to_string(&mut s)?;
552 let mut result = HashMap::new();
553 for l in s.lines() {
554 let mut sp = l.split(':');
555 match (
556 sp.next().and_then(Hash::from_base58),
557 sp.next().and_then(|s| s.parse().ok()),
558 ) {
559 (Some(h), Some(s)) => {
560 result.insert(h, s);
561 }
562 _ => {}
563 }
564 }
565 Ok(result)
566}
567
568pub fn read_changes_from_file<P: AsRef<Path>>(
569 changes_file: P,
570) -> Result<HashMap<Hash, ApplyTimestamp>> {
571 let mut file = File::open(changes_file)?;
572 read_changes(&mut file)
573}
574
575impl<U: Transaction, R> GenericTxn<U, R> {
576 pub fn new_patch<I: Iterator<Item = Hash>>(
577 &self,
578 branch: &Branch,
579 authors: Vec<String>,
580 name: String,
581 description: Option<String>,
582 timestamp: DateTime<Utc>,
583 changes: Vec<Change<ChangeContext<Hash>>>,
584 extra_dependencies: I,
585 flag: PatchFlags,
586 ) -> Patch {
587 let mut dependencies = self.dependencies(branch, changes.iter());
588 dependencies.extend(extra_dependencies);
589 Patch::Unsigned(UnsignedPatch {
590 header: PatchHeader {
591 authors,
592 name,
593 description,
594 timestamp,
595 flag,
596 },
597 dependencies,
598 changes,
599 })
600 }
601
602 pub fn dependencies<'a, I: Iterator<Item = &'a Change<ChangeContext<Hash>>>>(
603 &self,
604 branch: &Branch,
605 changes: I,
606 ) -> HashSet<Hash> {
607 let mut deps = HashSet::new();
608 let mut zombie_deps = HashSet::new();
609 for ch in changes {
610 match *ch {
611 Change::NewNodes {
612 ref up_context,
613 ref down_context,
614 ..
615 } => for c in up_context.iter().chain(down_context.iter()) {
616 match c.patch {
617 None | Some(Hash::None) => {}
618 Some(ref dep) => {
619 debug!("dependencies (line {}) += {:?}", line!(), dep);
620 deps.insert(dep.clone());
621 }
622 }
623 },
624 Change::NewEdges {
625 flag, ref edges, ..
626 } => {
627 for e in edges {
628 let (from, to) = if flag.contains(EdgeFlags::PARENT_EDGE) {
629 (&e.to, &e.from)
630 } else {
631 (&e.from, &e.to)
632 };
633
634 match from.patch {
635 None | Some(Hash::None) => {}
636 Some(ref h) => {
637 debug!("dependencies (line {}) += {:?}", line!(), h);
638 deps.insert(h.clone());
639 if flag.contains(EdgeFlags::DELETED_EDGE) {
640 let k = Key {
644 patch: self.get_internal(h.as_ref()).unwrap().to_owned(),
645 line: from.line.clone(),
646 };
647 self.edge_context_deps(branch, k, &mut zombie_deps)
648 }
649 }
650 }
651 match to.patch {
652 None | Some(Hash::None) => {}
653 Some(ref h) => {
654 debug!("dependencies (line {}) += {:?}", line!(), h);
655 deps.insert(h.clone());
656 if flag.contains(EdgeFlags::DELETED_EDGE) {
657 let k = Key {
661 patch: self.get_internal(h.as_ref()).unwrap().to_owned(),
662 line: to.line.clone(),
663 };
664 self.edge_context_deps(branch, k, &mut zombie_deps)
665 }
666 }
667 }
668 match e.introduced_by {
669 None | Some(Hash::None) => {}
670 Some(ref h) => {
671 debug!("dependencies (line {}) += {:?}", line!(), h);
672 zombie_deps.insert(h.clone());
673 }
674 }
675 }
676 }
677 }
678 }
679 let mut h = self.minimize_deps(&deps);
680 for z in zombie_deps.drain() {
681 h.insert(z);
682 }
683 h
684 }
685
686 pub fn minimize_deps(&self, deps: &HashSet<Hash>) -> HashSet<Hash> {
687 debug!("minimize_deps {:?}", deps);
688 let mut covered = HashSet::new();
689 let mut stack = Vec::new();
690 let mut seen = HashSet::new();
691 for dep_ext in deps.iter() {
692 let dep = self.get_internal(dep_ext.as_ref()).unwrap();
694 debug!("dep = {:?}", dep);
695 stack.clear();
696 stack.push((dep, false));
697 while let Some((current, on_path)) = stack.pop() {
698 let already_covered = covered.get(¤t).is_some() || (current != dep && {
701 let current_ext = self.get_external(current).unwrap();
702 deps.get(¤t_ext.to_owned()).is_some()
703 });
704 if already_covered {
705 for &(h, h_on_path) in stack.iter() {
708 if h_on_path {
709 debug!("covered: h {:?}", h);
710 covered.insert(h);
711 }
712 }
713 break;
714 }
715 if seen.insert(current) && !on_path {
721 stack.push((current, true));
722
723 for (_, parent) in self.iter_revdep(Some((current, None)))
724 .take_while(|k| k.0 == current)
725 {
726 stack.push((parent, false))
727 }
728 }
729 }
730 }
731
732 deps.iter()
733 .filter_map(|dep_ext| {
734 let dep = self.get_internal(dep_ext.as_ref()).unwrap();
735 if covered.get(&dep).is_none() {
736 Some(dep_ext.to_owned())
737 } else {
738 None
739 }
740 })
741 .collect()
742 }
743
744 fn edge_context_deps(&self, branch: &Branch, k: Key<PatchId>, deps: &mut HashSet<Hash>) {
745 for (_, edge) in self.iter_nodes(branch, Some((k, None)))
746 .take_while(|&(k_, _)| k_ == k)
747 .filter(|&(_, e_)| !e_.flag.contains(EdgeFlags::PARENT_EDGE))
748 {
749 if let Some(ext) = self.get_external(edge.introduced_by) {
750 deps.insert(ext.to_owned());
751 }
752 }
753 }
754}
755
756use backend::*;
757use sanakirja;
758
759impl<A: sanakirja::Transaction, R> GenericTxn<A, R> {
760 pub fn external_key(&self, key: &Key<PatchId>) -> Option<Key<Option<Hash>>> {
764 Some(Key {
765 patch: Some(self.external_hash(key.patch).to_owned()),
766 line: key.line,
767 })
768 }
769
770 pub fn external_hash(&self, key: PatchId) -> HashRef {
771 if key == ROOT_PATCH_ID {
772 ROOT_HASH.as_ref()
773 } else {
774 self.get_external(key).unwrap()
775 }
776 }
777
778 pub(crate) fn external_hash_opt(&self, h: Option<PatchId>) -> Option<Hash> {
779 h.map(|x| self.external_hash(x).to_owned())
780 }
781
782 pub(crate) fn external_key_opt(&self, h: Key<Option<PatchId>>) -> Key<Option<Hash>> {
783 Key {
784 line: h.line,
785 patch: self.external_hash_opt(h.patch),
786 }
787 }
788
789 pub fn new_internal(&self, ext: HashRef) -> PatchId {
793 let mut result = ROOT_PATCH_ID;
794 match ext {
795 HashRef::None => return result,
796 HashRef::Sha512(h) => result.clone_from_slice(&h[..PATCH_ID_SIZE]),
797 }
798 let mut first_random = PATCH_ID_SIZE;
799 loop {
800 if self.get_external(result).is_none() {
801 break;
802 }
803 if first_random > 0 {
804 first_random -= 1
805 };
806 for x in &mut result[first_random..].iter_mut() {
807 *x = rand::random()
808 }
809 }
810 result
811 }
812}