nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: bluss/rust-itertools
Pull request #317 (2018-11-24 09:43:20)

Bump quickcheck to 0.7 and Rust version to 1.22
Closes #253 


Patch:
diff --git a/.travis.yml b/.travis.yml
index 31817e4..faa6d94 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,14 +2,7 @@ language: rust
 sudo: false
 matrix:
   include:
-    - rust: 1.13.0
-      before_script:
-        # rand 0.4.2 requires rust 1.15, and rand-0.3.22 requires rand-0.4  :/
-        # manually hacking the lockfile due to the limitations of cargo#2773
-        - cargo generate-lockfile
-        - sed -i -e 's/"rand 0.[34].[0-9]\+/"rand 0.3.20/' Cargo.lock
-        - sed -i -e '/^name = "rand"/,/^$/s/version = "0.3.[0-9]\+"/version = "0.3.20"/' Cargo.lock
-    - rust: 1.15.0
+    - rust: 1.22.0
     - rust: stable
     - rust: beta
     - rust: nightly
diff --git a/Cargo.toml b/Cargo.toml
index da794f1..bc9b189 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,8 +20,11 @@ test = false
 [dependencies]
 either = { version = "1.0", default-features = false }
 
+[dev-dependencies]
+rand = "0.6"
+
 [dev-dependencies.quickcheck]
-version = "0.5"
+version = "0.7"
 default-features = false
 
 [dev-dependencies.permutohedron]


Test patch:
diff --git a/tests/quick.rs b/tests/quick.rs
index 6859758..38737ba 100644
--- a/tests/quick.rs
+++ b/tests/quick.rs
@@ -6,6 +6,7 @@
 #[macro_use] extern crate itertools;
 
 extern crate quickcheck;
+extern crate rand;
 
 use std::default::Default;
 
@@ -29,6 +30,8 @@ use itertools::free::{
     zip_eq,
 };
 
+use rand::Rng;
+use rand::seq::SliceRandom;
 use quickcheck::TestResult;
 
 /// Trait for size hint modifier types
@@ -78,8 +81,8 @@ impl qc::Arbitrary for Inexact {
         let ue_choices = &[0, ue_value, usize::max_value()];
         let oe_choices = &[0, oe_value, usize::max_value()];
         Inexact {
-            underestimate: *g.choose(ue_choices).unwrap(),
-            overestimate: *g.choose(oe_choices).unwrap(),
+            underestimate: *ue_choices.choose(g).unwrap(),
+            overestimate: *oe_choices.choose(g).unwrap(),
         }
     }
Repository: bluss/rust-ndarray
Pull request #218 (2016-09-19 19:32:00)

Add method .map_axis()


Patch:
diff --git a/src/impl_methods.rs b/src/impl_methods.rs
index 983a1b3a..1480fc53 100644
--- a/src/impl_methods.rs
+++ b/src/impl_methods.rs
@@ -1275,4 +1275,27 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
         }
         res
     }
+
+    /// Reduce the values along an axis into just one value, producing a new
+    /// array with one less dimension.
+    ///
+    /// Return the result as an `Array`.
+    pub fn map_axis<B, F>(&self, axis: Axis, mut mapping: F) -> Array<B, D::Smaller>
+        where D: RemoveAxis,
+              F: FnMut(ArrayView<A, Ix>) -> B,
+    {
+        let result_dim = self.dim().remove_axis(axis);
+        let view_len = self.shape().axis(axis);
+        let view_stride = self.strides.axis(axis);
+        let mut result = Vec::with_capacity(result_dim.size());
+        for map in self.subview(axis, 0) {
+            unsafe {
+                let view = ArrayView::new_(map, view_len, view_stride);
+                result.push(mapping(view));
+            }
+        }
+        unsafe {
+            Array::from_shape_vec_unchecked(result_dim, result)
+        }
+    }
 }


Test patch:
diff --git a/tests/array.rs b/tests/array.rs
index 225dd87b..73fc56aa 100644
--- a/tests/array.rs
+++ b/tests/array.rs
@@ -1062,3 +1062,18 @@ fn test_default() {
     let b = <Array<Foo, ()> as Default>::default();
     assert_eq!(b, arr0(Foo::default()));
 }
+
+#[test]
+fn test_map_axis() {
+    let a = arr2(&[[1, 2, 3],
+                   [4, 5, 6],
+                   [7, 8, 9],
+                   [10,11,12]]);
+
+    let b = a.map_axis(Axis(0), |view| view.scalar_sum());
+    let answer1 = arr1(&[22, 26, 30]);
+    assert_eq!(b, answer1);
+    let c = a.map_axis(Axis(1), |view| view.scalar_sum());
+    let answer2 = arr1(&[6, 15, 24, 33]);
+    assert_eq!(c, answer2);
+}
Repository: bluss/rust-ndarray
Pull request #266 (2017-01-24 14:45:22)

Add RcArray::into_owned() -> Array


Patch:
diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs
index 42d11641..16b70be3 100644
--- a/src/impl_owned_array.rs
+++ b/src/impl_owned_array.rs
@@ -1,4 +1,6 @@
 
+use std::rc::Rc;
+
 use imp_prelude::*;
 
 impl<A, D> ArrayBase<Vec<A>, D>
@@ -13,3 +15,22 @@ impl<A, D> ArrayBase<Vec<A>, D>
         self.data
     }
 }
+
+// RcArray
+impl<A, D> ArrayBase<Rc<Vec<A>>, D>
+    where A: Clone,
+          D: Dimension
+{
+    /// Convert an `RcArray` into `Array`; cloning the array elements to unshare
+    /// them if necessary.
+    pub fn into_owned(mut self) -> Array<A, D> {
+        <_>::ensure_unique(&mut self);
+        let data = Rc::try_unwrap(self.data).ok().unwrap();
+        ArrayBase {
+            data: data,
+            ptr: self.ptr,
+            dim: self.dim,
+            strides: self.strides,
+        }
+    }
+}


Test patch:
diff --git a/tests/array-construct.rs b/tests/array-construct.rs
index 8ba7bb23..ae9985d6 100644
--- a/tests/array-construct.rs
+++ b/tests/array-construct.rs
@@ -18,3 +18,14 @@ fn test_dimension_zero() {
     let a: Array3<f32> = Array3::from(vec![[[]], [[]], [[]]]);
     assert_eq!(vec![0.; 0], a.into_raw_vec());
 }
+
+#[test]
+fn test_rc_into_owned() {
+    let a = Array2::from_elem((5, 5), 1.).into_shared();
+    let mut b = a.clone();
+    b.fill(0.);
+    let mut c = b.into_owned();
+    c.fill(2.);
+    // test that they are unshared
+    assert!(!a.all_close(&c, 0.01));
+}
Repository: bluss/rust-ndarray
Pull request #267 (2017-01-24 22:20:37)

Implement Clone::clone_from for ArrayBase
This reuses Vec's .clone_from() in `Array`. No effect for ArrayView or
RcArray, of course.


Patch:
diff --git a/src/data_traits.rs b/src/data_traits.rs
index df510bfb..dcbe8c75 100644
--- a/src/data_traits.rs
+++ b/src/data_traits.rs
@@ -59,6 +59,13 @@ pub unsafe trait DataClone : Data {
     #[doc(hidden)]
     /// Unsafe because, `ptr` must point inside the current storage.
     unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem);
+
+    #[doc(hidden)]
+    unsafe fn clone_from_with_ptr(&mut self, other: &Self, ptr: *mut Self::Elem) -> *mut Self::Elem {
+        let (data, ptr) = other.clone_with_ptr(ptr);
+        *self = data;
+        ptr
+    }
 }
 
 unsafe impl<A> Data for Rc<Vec<A>> {
@@ -134,6 +141,17 @@ unsafe impl<A> DataClone for Vec<A>
         }
         (u, new_ptr)
     }
+
+    unsafe fn clone_from_with_ptr(&mut self, other: &Self, ptr: *mut Self::Elem) -> *mut Self::Elem {
+        let our_off = if size_of::<A>() != 0 {
+            (ptr as isize - other.as_ptr() as isize) /
+                          mem::size_of::<A>() as isize
+        } else {
+            0
+        };
+        self.clone_from(other);
+        self.as_mut_ptr().offset(our_off)
+    }
 }
 
 unsafe impl<'a, A> Data for ViewRepr<&'a A> {
diff --git a/src/impl_clone.rs b/src/impl_clone.rs
index b756804c..9626d945 100644
--- a/src/impl_clone.rs
+++ b/src/impl_clone.rs
@@ -20,6 +20,17 @@ impl<S: DataClone, D: Clone> Clone for ArrayBase<S, D> {
             }
         }
     }
+
+    /// `Array` implements `.clone_from()` to reuse an array's existing
+    /// allocation. Semantically equivalent to `*self = other.clone()`, but
+    /// potentially more efficient.
+    fn clone_from(&mut self, other: &Self) {
+        unsafe {
+            self.ptr = self.data.clone_from_with_ptr(&other.data, other.ptr);
+            self.dim.clone_from(&other.dim);
+            self.strides.clone_from(&other.strides);
+        }
+    }
 }
 
 impl<S: DataClone + Copy, D: Copy> Copy for ArrayBase<S, D> {}


Test patch:
diff --git a/tests/clone.rs b/tests/clone.rs
new file mode 100644
index 00000000..e6f66c3c
--- /dev/null
+++ b/tests/clone.rs
@@ -0,0 +1,20 @@
+
+extern crate ndarray;
+
+use ndarray::arr2;
+
+#[test]
+fn test_clone_from() {
+    let a = arr2(&[[1, 2, 3],
+                   [4, 5, 6],
+                   [7, 8, 9]]);
+    let b = arr2(&[[7, 7, 7]]);
+    let mut c = b.clone();
+    c.clone_from(&a);
+    assert_eq!(a, c);
+
+    let mut bv = b.view();
+    bv.clone_from(&a.view());
+    assert_eq!(&a, &bv);
+
+}
Repository: bluss/rust-ndarray
Pull request #268 (2017-01-29 13:47:42)

Test, doc, empty case for array![] macro


Patch:
diff --git a/src/free_functions.rs b/src/free_functions.rs
index 0bcad608..9d42d32f 100644
--- a/src/free_functions.rs
+++ b/src/free_functions.rs
@@ -11,8 +11,9 @@ use std::mem::{size_of, forget};
 
 use imp_prelude::*;
 
-/// Easily create an [**`Array`**](type.Array.html) of up to 3 dimensions.
-/// 
+/// Create an [**`Array`**](type.Array.html) with one, two or
+/// three dimensions.
+///
 /// ```
 /// #[macro_use(array)]
 /// extern crate ndarray;
@@ -20,9 +21,10 @@ use imp_prelude::*;
 /// fn main() {
 ///     let a1 = array![1, 2, 3, 4];
 ///
-///     let a2 = array![[1, 2], [3, 4]];
-/// 
-///     let a3 = array![[[1, 2], [3, 4]], 
+///     let a2 = array![[1, 2],
+///                     [3, 4]];
+///
+///     let a3 = array![[[1, 2], [3, 4]],
 ///                     [[5, 6], [7, 8]]];
 ///
 ///     assert_eq!(a1.shape(), &[4]);
@@ -30,12 +32,17 @@ use imp_prelude::*;
 ///     assert_eq!(a3.shape(), &[2, 2, 2]);
 /// }
 /// ```
+///
+/// This macro uses `vec![]`, and has the same ownership semantics;
+/// elements are moved into the resulting `Array`.
+///
+/// Use `array![...].into_shared()` to create an `RcArray`.
 #[macro_export]
 macro_rules! array {
-    ($([$([$($x:expr),*]),*]),*) => {{
+    ($([$([$($x:expr),*]),+]),+) => {{
         $crate::Array3::from(vec![$([$([$($x,)*],)*],)*])
     }};
-    ($([$($x:expr),*]),*) => {{
+    ($([$($x:expr),*]),+) => {{
         $crate::Array2::from(vec![$([$($x,)*],)*])
     }};
     ($($x:expr),*) => {{


Test patch:
diff --git a/tests/array.rs b/tests/array.rs
index 072d9cd5..ab4d1c84 100644
--- a/tests/array.rs
+++ b/tests/array.rs
@@ -1136,4 +1136,17 @@ fn array_macros() {
     assert_eq!(a2, arr2(&[[1, 2], [3, 4], [5, 6]]));
     let a3 = array![[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
     assert_eq!(a3, arr3(&[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]));
-}
\ No newline at end of file
+
+    let s = String::from("abc");
+    let a2s = array![[String::from("w"), s],
+                     [String::from("x"), String::from("y")]];
+    assert_eq!(a2s[[0, 0]], "w");
+    assert_eq!(a2s[[0, 1]], "abc");
+    assert_eq!(a2s[[1, 0]], "x");
+    assert_eq!(a2s[[1, 1]], "y");
+
+    let empty1: Array<f32, Ix1> = array![];
+    assert_eq!(empty1, array![]);
+    let empty2: Array<f32, Ix2> = array![[]];
+    assert_eq!(empty2, array![[]]);
+}
Repository: bluss/rust-ndarray
Pull request #309 (2017-04-09 12:55:34)

parallel: Fix .collect() for the element par iters
- They must not define opt_len to return Some (reserved for indexed iterators).
- Added test that shows problem and verifies the fix


Patch:
diff --git a/parallel/src/par.rs b/parallel/src/par.rs
index 7aecdfae..4ad10d15 100644
--- a/parallel/src/par.rs
+++ b/parallel/src/par.rs
@@ -162,7 +162,7 @@ macro_rules! par_iter_view_wrapper {
         }
 
         fn opt_len(&mut self) -> Option<usize> {
-            Some(self.iter.len())
+            None
         }
     }
 


Test patch:
diff --git a/parallel/tests/rayon.rs b/parallel/tests/rayon.rs
index 4739e016..9c63af47 100644
--- a/parallel/tests/rayon.rs
+++ b/parallel/tests/rayon.rs
@@ -40,3 +40,13 @@ fn test_regular_iter() {
     println!("{:?}", a.slice(s![..10, ..5]));
     assert_eq!(s, a.scalar_sum());
 }
+
+#[test]
+fn test_regular_iter_collect() {
+    let mut a = Array2::<f64>::zeros((M, N));
+    for (i, mut v) in a.axis_iter_mut(Axis(0)).enumerate() {
+        v.fill(i as _);
+    }
+    let v = a.view().into_par_iter().map(|&x| x).collect::<Vec<_>>();
+    assert_eq!(v.len(), a.len());
+}
Repository: bluss/rust-ndarray
Pull request #336 (2017-07-28 09:00:56)

Impl `From<ArrayN>` for ArrayD, for N in 0..6
* Implement the From<ArrayN> trait for ArrayD to allow conversion
  into dynamic dimensional array.
* Add some tests.


Patch:
diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs
index 929a0623..03f5bb66 100644
--- a/src/dimension/dimension_trait.rs
+++ b/src/dimension/dimension_trait.rs
@@ -371,6 +371,11 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
             .map_or(Axis(0), |ax| ax.axis())
     }
 
+    /// Convert the dimensional into a dynamic dimensional (IxDyn).
+    fn into_dyn(self) -> IxDyn {
+        IxDyn(self.slice())
+    }
+
     #[doc(hidden)]
     fn try_remove_axis(&self, axis: Axis) -> Self::Smaller;
 
diff --git a/src/impl_methods.rs b/src/impl_methods.rs
index a416b6ba..30e3185d 100644
--- a/src/impl_methods.rs
+++ b/src/impl_methods.rs
@@ -1043,6 +1043,25 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
         }
     }
 
+    /// Convert a static dimensional array to a dynamic dimensional array.
+    ///
+    /// ```
+    /// use ndarray::{arr2, ArrayD};
+    ///
+    /// assert!(
+    ///     arr2(&[[1, 2], [3, 4]]).into_dyn()
+    ///     == ArrayD::from_shape_vec(vec![2, 2], vec![1, 2, 3, 4]).unwrap()
+    /// );
+    /// ```
+    pub fn into_dyn(self) -> ArrayBase<S, IxDyn> {
+        ArrayBase {
+            data: self.data,
+            ptr: self.ptr,
+            dim: self.dim.into_dyn(),
+            strides: self.strides.into_dyn(),
+        }
+    }
+
     /// Act like a larger size and/or shape array by *broadcasting*
     /// into a larger shape, if possible.
     ///


Test patch:
diff --git a/tests/into-ixdyn.rs b/tests/into-ixdyn.rs
new file mode 100644
index 00000000..d9ec714e
--- /dev/null
+++ b/tests/into-ixdyn.rs
@@ -0,0 +1,16 @@
+extern crate ndarray;
+
+use ndarray::prelude::*;
+
+#[test]
+fn test_arr0_into_dyn() {
+    assert!(arr0(1.234).into_dyn()[IxDyn(&[])] == 1.234);
+}
+
+#[test]
+fn test_arr2_into_arrd_nonstandard_strides() {
+    let arr = Array2::from_shape_fn((12, 34).f(), |(i, j)| i * 34 + j).into_dyn();
+    let brr = ArrayD::from_shape_fn(vec![12, 34], |d| d[0] * 34 + d[1]);
+    
+    assert!(arr == brr);
+}
Repository: cayleygraph/cayley
Pull request #887 (2019-11-07 23:10:11)

Implement HasPath helper
Currently we only allow to trace a single path in `Has`. This PR allows to pass an arbitrary subtree by calling the new `HasPath` helper.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/cayleygraph/cayley/887)
<!-- Reviewable:end -->



Patch:
diff --git a/query/path/morphism_apply_functions.go b/query/path/morphism_apply_functions.go
index ee88eb7..e680c1f 100644
--- a/query/path/morphism_apply_functions.go
+++ b/query/path/morphism_apply_functions.go
@@ -88,6 +88,16 @@ func filterMorphism(filt []shape.ValueFilter) morphism {
 	}
 }
 
+// hasPathMorphism is a generic form of Has morphism - it accepts a subtree that will be checked on the current path.
+func hasPathMorphism(p *Path) morphism {
+	return morphism{
+		Reversal: func(ctx *pathContext) (morphism, *pathContext) { return hasPathMorphism(p), ctx },
+		Apply: func(in shape.Shape, ctx *pathContext) (shape.Shape, *pathContext) {
+			return shape.IntersectShapes(in, p.Shape()), ctx
+		},
+	}
+}
+
 // hasMorphism is the set of nodes that is reachable via either a *Path, a
 // single node.(string) or a list of nodes.([]string).
 func hasMorphism(via interface{}, rev bool, nodes ...quad.Value) morphism {
diff --git a/query/path/path.go b/query/path/path.go
index f10a577..a6e7d10 100644
--- a/query/path/path.go
+++ b/query/path/path.go
@@ -428,6 +428,13 @@ func (p *Path) SaveOptionalReverse(via interface{}, tag string) *Path {
 	return np
 }
 
+// HasPath limits the paths to be ones where the current nodes have a given subpath.
+func (p *Path) HasPath(p2 *Path) *Path {
+	np := p.clone()
+	np.stack = append(np.stack, hasPathMorphism(p2.Reverse()))
+	return np
+}
+
 // Has limits the paths to be ones where the current nodes have some linkage
 // to some known node.
 func (p *Path) Has(via interface{}, nodes ...quad.Value) *Path {


Test patch:
diff --git a/query/path/pathtest/pathtest.go b/query/path/pathtest/pathtest.go
index 03dcc3d..fc92d54 100644
--- a/query/path/pathtest/pathtest.go
+++ b/query/path/pathtest/pathtest.go
@@ -274,6 +274,11 @@ func testSet(qs graph.QuadStore) []test {
 			}),
 			expect: []quad.Value{vBob, vDani, vEmily, vFred},
 		},
+		{
+			message: "has path",
+			path:    StartPath(qs).HasPath(StartMorphism().Out(vStatus).Is(vCool)),
+			expect:  []quad.Value{vGreg, vDani, vBob},
+		},
 		{
 			message: "string prefix",
 			path: StartPath(qs).Filters(shape.Wildcard{
Repository: coreos/go-oidc
Pull request #260 (2020-07-17 06:43:52)

oidc: separate NewProvider context and Verifier context
Because NewProvider needs the RemoteKeySet for UserInfo responses, just
create a new context for the RemoteKeySet. RemoteKeySet should be
garbage collected once it's not used, so it's not clear we need the
cancelation.

Updates #232
Updates #214


Patch:
diff --git a/oidc/oidc.go b/oidc/oidc.go
index 911718e..c9e18e4 100644
--- a/oidc/oidc.go
+++ b/oidc/oidc.go
@@ -55,6 +55,17 @@ func ClientContext(ctx context.Context, client *http.Client) context.Context {
 	return context.WithValue(ctx, oauth2.HTTPClient, client)
 }
 
+// cloneContext copies a context's bag-of-values into a new context that isn't
+// associated with its cancelation. This is used to initialize remote keys sets
+// which run in the background and aren't associated with the initial context.
+func cloneContext(ctx context.Context) context.Context {
+	cp := context.Background()
+	if c, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok {
+		cp = ClientContext(cp, c)
+	}
+	return cp
+}
+
 func doRequest(ctx context.Context, req *http.Request) (*http.Response, error) {
 	client := http.DefaultClient
 	if c, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok {
@@ -153,7 +164,7 @@ func NewProvider(ctx context.Context, issuer string) (*Provider, error) {
 		userInfoURL:  p.UserInfoURL,
 		algorithms:   algs,
 		rawClaims:    body,
-		remoteKeySet: NewRemoteKeySet(ctx, p.JWKSURL),
+		remoteKeySet: NewRemoteKeySet(cloneContext(ctx), p.JWKSURL),
 	}, nil
 }
 


Test patch:
diff --git a/oidc/oidc_test.go b/oidc/oidc_test.go
index 00c05c3..3e4b2a3 100644
--- a/oidc/oidc_test.go
+++ b/oidc/oidc_test.go
@@ -300,6 +300,19 @@ func TestNewProvider(t *testing.T) {
 	}
 }
 
+func TestCloneContext(t *testing.T) {
+	ctx := context.Background()
+	if _, ok := cloneContext(ctx).Value(oauth2.HTTPClient).(*http.Client); ok {
+		t.Errorf("cloneContext(): expected no *http.Client from empty context")
+	}
+
+	c := &http.Client{}
+	ctx = ClientContext(ctx, c)
+	if got, ok := cloneContext(ctx).Value(oauth2.HTTPClient).(*http.Client); !ok || c != got {
+		t.Errorf("cloneContext(): expected *http.Client from context")
+	}
+}
+
 type testServer struct {
 	contentType string
 	userInfo    string
Repository: osbuild/osbuild-composer
Pull request #219 (2020-01-31 23:09:55)

Switch blueprint commit to use a random SHA-1
Generating a SHA-1 based on time is not safe. A collision can easily be
generated, and if parallel operations are used they will eventually
collide. This reads random bytes and uses them for the SHA-1 hash. It
will return an error if the rand.Read() fails.


Patch:
diff --git a/internal/store/store.go b/internal/store/store.go
index a574d7959..25392fdff 100644
--- a/internal/store/store.go
+++ b/internal/store/store.go
@@ -4,9 +4,11 @@ package store
 
 import (
 	"bytes"
+	"crypto/rand"
 	"crypto/sha1"
 	"encoding/hex"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -223,6 +225,19 @@ func writeFileAtomically(filename string, data []byte, mode os.FileMode) error {
 	return nil
 }
 
+func randomSHA1String() (string, error) {
+	hash := sha1.New()
+	data := make([]byte, 20)
+	n, err := rand.Read(data)
+	if err != nil {
+		return "", err
+	} else if n != 20 {
+		return "", errors.New("randomSHA1String: short read from rand")
+	}
+	hash.Write(data)
+	return hex.EncodeToString(hash.Sum(nil)), nil
+}
+
 func (s *Store) change(f func() error) error {
 	s.mu.Lock()
 	defer s.mu.Unlock()
@@ -351,13 +366,10 @@ func bumpVersion(str string) string {
 
 func (s *Store) PushBlueprint(bp blueprint.Blueprint, commitMsg string) {
 	s.change(func() error {
-		hash := sha1.New()
-		// Hash timestamp to create unique hash
-		hash.Write([]byte(time.Now().String()))
-		// Get hash as a byte slice
-		commitBytes := hash.Sum(nil)
-		// Get hash as a hex string
-		commit := hex.EncodeToString(commitBytes)
+		commit, err := randomSHA1String()
+		if err != nil {
+			return err
+		}
 		timestamp := time.Now().Format("2006-01-02T15:04:05Z")
 		change := blueprint.Change{
 			Commit:    commit,


Test patch:
diff --git a/internal/store/store_test.go b/internal/store/store_test.go
index be7b3a4b3..c36efe743 100644
--- a/internal/store/store_test.go
+++ b/internal/store/store_test.go
@@ -28,3 +28,13 @@ func TestBumpVersion(t *testing.T) {
 		}
 	}
 }
+
+func TestRandomSHA1String(t *testing.T) {
+	hash, err := randomSHA1String()
+	if err != nil {
+		t.Fatalf("RandomSHA1String failed: %s", err)
+	}
+	if len(hash) != 40 {
+		t.Fatalf("RandomSHA1String failed: hash is not 40 characters")
+	}
+}
Repository: osbuild/osbuild-composer
Pull request #224 (2020-02-06 00:19:20)

api: Add TOML support for workspace POST
composer-cli pushes blueprints to the workspace using TOML not JSON.
This also adds a test.


Patch:
diff --git a/internal/weldr/api.go b/internal/weldr/api.go
index e59e4f8eb..259008c58 100644
--- a/internal/weldr/api.go
+++ b/internal/weldr/api.go
@@ -1127,21 +1127,29 @@ func (api *API) blueprintsWorkspaceHandler(writer http.ResponseWriter, request *
 	}
 
 	contentType := request.Header["Content-Type"]
-	if len(contentType) != 1 || contentType[0] != "application/json" {
+	if len(contentType) == 0 {
 		errors := responseError{
 			ID:  "BlueprintsError",
-			Msg: "'blueprint must be json'",
+			Msg: "missing Content-Type header",
 		}
 		statusResponseError(writer, http.StatusBadRequest, errors)
 		return
 	}
 
 	var blueprint blueprint.Blueprint
-	err := json.NewDecoder(request.Body).Decode(&blueprint)
+	var err error
+	if contentType[0] == "application/json" {
+		err = json.NewDecoder(request.Body).Decode(&blueprint)
+	} else if contentType[0] == "text/x-toml" {
+		_, err = toml.DecodeReader(request.Body, &blueprint)
+	} else {
+		err = errors.New("blueprint must be in json or toml format")
+	}
+
 	if err != nil {
 		errors := responseError{
 			ID:  "BlueprintsError",
-			Msg: "400 Bad Request: The browser (or proxy) sent a request that this server could not understand.",
+			Msg: "400 Bad Request: The browser (or proxy) sent a request that this server could not understand: " + err.Error(),
 		}
 		statusResponseError(writer, http.StatusBadRequest, errors)
 		return


Test patch:
diff --git a/internal/weldr/api_test.go b/internal/weldr/api_test.go
index b0cb33a87..ad22e3d9b 100644
--- a/internal/weldr/api_test.go
+++ b/internal/weldr/api_test.go
@@ -101,7 +101,7 @@ version = "2.4.*"`
 	}
 }
 
-func TestBlueprintsWorkspace(t *testing.T) {
+func TestBlueprintsWorkspaceJSON(t *testing.T) {
 	var cases = []struct {
 		Method         string
 		Path           string
@@ -119,6 +119,29 @@ func TestBlueprintsWorkspace(t *testing.T) {
 	}
 }
 
+func TestBlueprintsWorkspaceTOML(t *testing.T) {
+	blueprint := `
+name = "test"
+description = "Test"
+version = "0.0.0"
+
+[[packages]]
+name = "httpd"
+version = "2.4.*"`
+
+	req := httptest.NewRequest("POST", "/api/v0/blueprints/workspace", bytes.NewReader([]byte(blueprint)))
+	req.Header.Set("Content-Type", "text/x-toml")
+	recorder := httptest.NewRecorder()
+
+	api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
+	api.ServeHTTP(recorder, req)
+
+	r := recorder.Result()
+	if r.StatusCode != http.StatusOK {
+		t.Fatalf("unexpected status %v", r.StatusCode)
+	}
+}
+
 func TestBlueprintsInfo(t *testing.T) {
 	var cases = []struct {
 		Method         string