summaryrefslogtreecommitdiff
path: root/sys/src/cmd/git/import
blob: 102a4fdcdd63bcae964f95d279d66b417298f093 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/bin/rc
rfork ne
. /sys/lib/git/common.rc

diffpath=/tmp/gitimport.$pid.diff
fn sigexit {
	rm -f $diffpath
}


fn apply @{
	git/fs
	amail=''
	aname=''
	msg=''
	whoami
	parents='-p'^`{git/query HEAD}
	branch=`{git/branch}
	if(test -e $gitfs/branch/$branch/tree)
		refpath=.git/refs/$branch
	if not if(test -e $gitfs/object/$branch/tree)
		refpath=.git/HEAD
	if not
		die 'invalid branch:' $branch
	awk '
	BEGIN{
		state="headers"
	}
	state=="headers" && /^From:/ {
		sub(/^From:[ \t]*/, "", $0);
		aname=$0;
		amail=$0;
		sub(/[ \t]*<.*$/, "", aname);
		sub(/^[^<]*</, "", amail);
		sub(/>[^>]*$/, "", amail);
	}
	state=="headers" && /^Date:/{
		sub(/^Date:[ \t]*/, "", $0)
		date=$0
	}
	state=="headers" && /^Subject:/{
		sub(/^Subject:[ \t]*(\[[^\]]*\][ \t]*)*/, "", $0);
		gotmsg = 1
		print > "/env/msg"
	}
	state=="headers" && /^$/ {
		state="body"
	}
	(state=="headers" || state=="body") && (/^diff / || /^---( |$)/){
		state="diff"
	}
	state=="body" && /^[ 	]*$/ {
		empty=1
		next
	}
	state=="body" {
		if(empty)
			printf "\n" > "/env/msg"
		empty=0
		sub(/[ 	]+$/, "")
		print > "/env/msg"
	}
	state=="diff" {
		print > ENVIRON["diffpath"]
	}
	END{
		if(state != "diff")
			exit("malformed patch: " state);
		if(aname == "" || amail == "" || date == "" || gotmsg == "")
			exit("missing headers");
		printf "%s", aname > "/env/aname"
		printf "%s", amail > "/env/amail"
		printf "%s", date > "/env/date"
	}
	' || die 'could not import:' $status

	# force re-reading env
	rc -c '
		date=`{seconds $date}
		files=`$nl{patch -np1 < $diffpath}
		if(! git/walk -q $files){
			>[1=2] {
				echo patch would clobber files:
				git/walk $files
				exit clobber
			}
		}
		echo applying $msg | sed 1q
		if(! files=`$nl{patch -p1 < $diffpath})
			die ''patch failed''
		for(f in $files){
			if(test -e $f)
				git/add $f
			if not
				git/add -r $f
		}
		git/walk -fRMA $files
		if(~ $#nocommit 0){
			if(hash=`{git/save -n $aname -e $amail -N $name -E $email -m $msg -d $date $parents $files})
				echo $hash > $refpath
		}
		status=''''
	'
}

gitup

flagfmt='n:nocommit'; args='file ...'
eval `''{aux/getflags $*} || exec aux/usage

patches=(/fd/0)
if(! ~ $#* 0)
	patches=$*
for(p in $patches){
	# upas serves the decoded header and body separately,
	# so we cat them together when applying a upas message.
	#
	# this allows mime-encoded or line-wrapped patches.
	if(test -d $p && test -f $p/header && test -f $p/body)
		{{cat $p/header; echo; cat $p/body} | apply} || die $status
	if not
		apply < $p
}
exit ''